Reputation: 8487
I have a horizontal recycler view called imageRecyclerView
where each column consists solely of one ImageView
. The adapter class for the recycler view is called ImageAdapter
. The dataset of imageRecyclerView
's adapter is an ArrayList
of strings that contain URLs. The ArrayList
is called currentImageURLs
.
Note - the purpose of all this code is to load images into imageRecyclerView
one at a time.
In the onBindViewHolder
method of my ImageAdapter
class I have the following code. This code loads an image from the adapter's dataset into an ImageView
. The code also waits until the image has been loaded into the ImageView
before calling recursivelyLoadURLs
to add a new item to the adapter's dataset.
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)
The method recursivelyLoadURLs
is in the parent Activity class. In essence, what this method does is
1] add another URL to imageRecyclerView
's adapter's dataset and
2] call notifyDataSetChanged
so imageRecyclerView
updates:
fun recursivelyLoadURLs() {
if (currentImageURLs.size >= targetImageURLs.size) {
return
}
currentImageURLs.add(targetImageURLs[currentImageURLs.size])
//The code crashes on this line
mainview.imageRecyclerView.adapter.notifyDataSetChanged()
}
However, the code is crashing with the exception java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
on the line labeled in the above code sample.
I suspect this is happening because imageRecyclerView
is still computing a layout when notifyDataSetChanged
is being called.
How can I delay calling context.recursivelyLoadURLs
until the layout has finished being computed?
Or, how can I add a delay inside recursivelyLoadURLs
, so that notifyDataSetChanged
is only called once imageRecyclerView
has finished computing its new layout?
Upvotes: 0
Views: 1911
Reputation: 8487
tompee has suggested posting a Runnable in order to guarantee the recycler view has layed out its children before running notifyDataSetChanged
.
As such, I replaced notifyDataSetChanged
with
mainview.imageRecyclerView.post({
mainview.imageRecyclerView.adapter.notifyDataSetChanged()
})
and this solved the problem.
Upvotes: 3
Reputation: 4085
You can read the documentation on RecyclerView.Adapter.notifyDataSetChanged
This event does not specify what about the data set has changed, forcing any observers to assume that all existing items and structure may no longer be valid. LayoutManagers will be forced to fully rebind and relayout all visible views.
If you are writing an adapter it will always be more efficient to use the more specific change events if you can. Rely on notifyDataSetChanged() as a last resort.
Here's some tips that might help *hope it helps :)
notifyDataSetChanged()
, especially in your onBindViewHolder. Use notifyItemChanged(position)
instead. It's much more efficient and cost less memory.notifyDataSetChanged()
, use it AFTER you are ready with ALL of your data (maybe have it when currentImageURLs.size >= targetImageURLs.size
)Upvotes: 0