You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android:如何使用unregisterAdapterDataObserver取消适配器待处理更新

How to Cancel Pending Network Requests in Your Android Adapter When Updating the List

Hey there! Let’s break down how to solve this problem properly—first, let’s clear up a common misunderstanding about that hasPendingAdapterUpdates() method you found:

hasPendingAdapterUpdates() only checks if the RecyclerView has pending UI update tasks (like pending notifyDataSetChanged() calls or item animations). It cannot cancel your network requests, since those are separate from the RecyclerView’s UI update pipeline.

To stop in-flight image requests from updating your adapter when a new list comes in, you need to manage the lifecycle of those network requests directly. Here are two common approaches depending on how you’re loading images:


1. Using an Image Loading Library (Glide/Picasso)

Most popular image loading libraries have built-in tools to cancel requests, which is the easiest and most reliable way to handle this.

Example with Glide

Glide automatically ties requests to the lifecycle of your Views, but you can explicitly cancel requests when updating your list:

class YourAdapter : RecyclerView.Adapter<YourAdapter.ViewHolder>() {
    private var currentItems: List<YourModel> = emptyList()
    private val glide = Glide.with(YourApplication.getAppContext())
    private var yourRecyclerView: RecyclerView? = null

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        yourRecyclerView = recyclerView
    }

    fun updateList(newItems: List<YourModel>) {
        // Cancel all active image requests for visible views
        cancelActiveImageRequests()
        currentItems = newItems
        notifyDataSetChanged()
    }

    private fun cancelActiveImageRequests() {
        yourRecyclerView?.let { rv ->
            for (i in 0 until rv.childCount) {
                val viewHolder = rv.getChildViewHolder(rv.getChildAt(i)) as ViewHolder
                glide.clear(viewHolder.imageView)
            }
        }
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = currentItems[position]
        glide.load(item.imageUrl)
            .into(holder.imageView)
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val imageView: ImageView = itemView.findViewById(R.id.your_image_view)
    }
}

Example with Picasso

Picasso works similarly—you can call cancelRequest() on the ImageView tied to the request:

class YourAdapter : RecyclerView.Adapter<YourAdapter.ViewHolder>() {
    private var currentItems: List<YourModel> = emptyList()
    private var yourRecyclerView: RecyclerView? = null

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        yourRecyclerView = recyclerView
    }

    fun updateList(newItems: List<YourModel>) {
        yourRecyclerView?.let { rv ->
            for (i in 0 until rv.childCount) {
                val viewHolder = rv.getChildViewHolder(rv.getChildAt(i)) as ViewHolder
                Picasso.get().cancelRequest(viewHolder.imageView)
            }
        }
        currentItems = newItems
        notifyDataSetChanged()
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = currentItems[position]
        Picasso.get().load(item.imageUrl).into(holder.imageView)
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val imageView: ImageView = itemView.findViewById(R.id.your_image_view)
    }
}

2. Manual Network Requests (OkHttp/Retrofit)

If you’re handling image requests manually with OkHttp or Retrofit, you’ll need to track all active requests and cancel them when updating the list:

class YourAdapter : RecyclerView.Adapter<YourAdapter.ViewHolder>() {
    private var currentItems: List<YourModel> = emptyList()
    private val pendingRequests = mutableListOf<Call<Bitmap>>()
    private val imageApi = Retrofit.Builder()
        .baseUrl("your_base_url/")
        .addConverterFactory(BitmapConverterFactory.create())
        .build()
        .create(ImageApi::class.java)

    fun updateList(newItems: List<YourModel>) {
        // Cancel all pending requests and clear the list
        cancelAllPendingRequests()
        currentItems = newItems
        notifyDataSetChanged()
    }

    private fun cancelAllPendingRequests() {
        pendingRequests.forEach { it.cancel() }
        pendingRequests.clear()
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = currentItems[position]
        val imageCall = imageApi.fetchImage(item.imageUrl)
        
        pendingRequests.add(imageCall)
        imageCall.enqueue(object : Callback<Bitmap> {
            override fun onResponse(call: Call<Bitmap>, response: Response<Bitmap>) {
                // Only update the view if the request wasn't canceled and the response is valid
                if (!call.isCanceled && response.isSuccessful) {
                    response.body()?.let { holder.imageView.setImageBitmap(it) }
                }
                // Remove the completed request from our tracking list
                pendingRequests.remove(call)
            }

            override fun onFailure(call: Call<Bitmap>, t: Throwable) {
                pendingRequests.remove(call)
            }
        })
    }

    // Don't forget to cancel requests when the adapter is detached from the RecyclerView
    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        super.onDetachedFromRecyclerView(recyclerView)
        cancelAllPendingRequests()
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val imageView: ImageView = itemView.findViewById(R.id.your_image_view)
    }

    // Define your Retrofit API interface
    interface ImageApi {
        @GET
        fun fetchImage(@Url imageUrl: String): Call<Bitmap>
    }
}

Key Notes

  • Always cancel requests when the adapter is detached from the RecyclerView (using onDetachedFromRecyclerView()) to avoid memory leaks.
  • For manual requests, always check call.isCanceled before updating the View—this prevents canceled requests from trying to modify a View that might be recycled for the new list.

内容的提问来源于stack exchange,提问作者Vanshika Arora

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:47:54