When updating RecycleView using DiffUtils ImageViews are flickering

Viewed 543

In my RecyclewView's adapter I am using DiffUtils to update only those items which were modified. While doing this I've noticed that ImageViews are flickering on every update and while debugging I found out that onCreateViewHolder method of my adapter is being called everytime I update the data, so viewholders are not being reused like they should. When I get rid of DiffUtil and use simple notifyDataSetChanged flickering dissapears. So why are those ViewHolders being recreated and how can I fix that?

Here is my DiffUtil callback:

class MyDiffUtilCallback(val newList: List<Item>, val oldList: List<Item>) : DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
    return newList[newItemPosition].id == oldList[oldItemPosition].id
}

override fun getOldListSize(): Int = oldList.size

override fun getNewListSize(): Int = newList.size

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
    return newList[newItemPosition] == oldList[oldItemPosition]
}

}

And how I update my adapter:

fun updateItems(items: List<Item>) {
    val diff = DiffUtil.calculateDiff(MyDiffUtilCallback(items, this.items))
    this.items = items
    diff.dispatchUpdatesTo(this)
}

EDIT: I looked into the issue some more and noticed that viewholders are also being recreated when using notifyDataSetChanged, I always thought that during update viewholders are being reused but I guess that is not the case. Anyway image flickering is still visible only when using DiffUtil and not notifyDataSetChanged and I don't know why

1 Answers

In your code, instead of below code

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): 
Boolean {
    return newList[newItemPosition] == oldList[oldItemPosition]
}

Use this.

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): 
Boolean {
    return newList[newItemPosition].id == oldList[oldItemPosition].id
}

because when you compare two objects they compare by memory reference, I think in this case while preparing new list you are not using old lists' same objects, so you should check whether they are equal by using their unique id of your custom data model "Item". But in your case it is calling onCreateViewHolder again, It should not happen here, Try this approach once, and By the way, are you using adapter supporting multiple types of items, If yes, this could be possible, as In changed list you are getting new types of items, which were not created yet, If we did not have those types of items in the previous old list.

Related