如何避免IllegalStateException调用notifyDataSetChanged?

时间:2018-06-08 01:26:56

标签: android kotlin android-recyclerview android-glide illegalstateexception

我有一个名为imageRecyclerView的水平回收视图,其中每列只包含一个ImageView。 Recycler视图的适配器类称为ImageAdapterimageRecyclerView适配器的数据集是包含URL的ArrayList个字符串。 ArrayList被称为currentImageURLs

注意 - 所有这些代码的目的是一次将图像加载到imageRecyclerView中。

onBindViewHolder类的ImageAdapter方法中,我有以下代码。此代码将适配器数据集中的图像加载到ImageView。在调用ImageView之前,代码还会等待图像加载到recursivelyLoadURLs,然后将新项添加到适配器的数据集中。

    Glide.with(context)
            //items[[position] is a string that contains a URL 
            .load(items[position])
            .listener(object : RequestListener<Drawable> {
                override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
                    holder.progressBar.visibility = View.GONE
                    context.recursivelyLoadURLs()
                    return false
                }

                override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                    holder.progressBar.visibility = View.GONE
                    context.recursivelyLoadURLs()
                    return false
                }

            })
            .apply(RequestOptions()
                    .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC))
            .into(holder.imageView)

方法recursivelyLoadURLs位于父Activity类中。从本质上讲,这种方法的作用是

1]为imageRecyclerView的适配器数据集添加另一个网址

2]致电notifyDataSetChanged,以便imageRecyclerView更新:

fun recursivelyLoadURLs() {


    if (currentImageURLs.size >= targetImageURLs.size) {
        return
    }

    currentImageURLs.add(targetImageURLs[currentImageURLs.size])

    //The code crashes on this line
    mainview.imageRecyclerView.adapter.notifyDataSetChanged()


}

但是,代码在上面代码示例中标记的行上发生异常java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling时崩溃。

我怀疑这种情况正在发生,因为imageRecyclerView在调用notifyDataSetChanged时仍在计算布局。

如何在布局完成计算之前延迟调用context.recursivelyLoadURLs

或者,如何在recursivelyLoadURLs内添加延迟,以便notifyDataSetChanged仅在imageRecyclerView计算完新布局后调用?

2 个答案:

答案 0 :(得分:1)

tompee建议发布一个Runnable,以确保回收者视图在运行notifyDataSetChanged之前已经布置了其子项。

因此,我将notifyDataSetChanged替换为

    mainview.imageRecyclerView.post({
        mainview.imageRecyclerView.adapter.notifyDataSetChanged()
    })

这解决了这个问题。

答案 1 :(得分:0)

您可以阅读RecyclerView.Adapter.notifyDataSetChanged

上的文档
  

此事件未指定数据集的更改内容,强制任何观察者假定所有现有项目和结构可能不再有效。 LayoutManagers将被迫完全重新绑定并重新布局所有可见视图。

     

如果您正在编写适配器,则尽可能使用更具体的更改事件会更有效。依靠notifyDataSetChanged()作为最后的手段。

以下是一些可能有用的提示*希望它有所帮助:)

  1. 尽量不要使用notifyDataSetChanged(),尤其是在onBindViewHolder中。请改用notifyItemChanged(position)。它效率更高,内存成本更低。
  2. 如果您确实需要使用notifyDataSetChanged(),请在准备好所有数据后使用它(可能在currentImageURLs.size >= targetImageURLs.size时使用)