Speed up Your Android RecyclerView Using DiffUtil | raywenderlich.com

Learn how to update the Android RecyclerView using DiffUtil to improve the performance. Also learn how it adds Animation to RecyclerView.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/21954410-speed-up-your-android-recyclerview-using-diffutil
1 Like

Can we get a the same explanation of onBindViewHolder for getChangePayload with numbers? Thanks a lot.

Hello archermiya,

Of course. Here it goes:

override fun getChangePayload(oldItem: Item, newItem: Item): Any? {
  //1
  if (oldItem.id == newItem.id) {
    //2
    return if (oldItem.done == newItem.done) {
      super.getChangePayload(oldItem, newItem)
    } else {
      //3
      val diff = Bundle()
      diff.putBoolean(ARG_DONE, newItem.done)
      diff
    }
  }

  return super.getChangePayload(oldItem, newItem)
}

Here’s a step-by-step breakdown of this logic:

  1. The getChangePayload function is called with two arguments: oldItem and newItem. As the name suggests it corresponds to the existing item and the new one. You’re only interested when both objects are the same, in this case, this means they have the same id.
  2. In this example, you’re only considering the field done. So if both objects have the same value you can call its super and return, because there’s nothing more that you can do.
  3. On the contrary, if the values are different you want to identify this change and return it. So you can later access it from the update function.

If you need any more information, please, don’t hesitate to ask :].

2 Likes

If we call the super which part of the onBindViewholder is being called?

Is it the empty payload part?

if (payloads.isEmpty() || payloads[0] !is Bundle)
                holder.bind(domain) // Full update/binding

Hello archeremiya,

If super.getChangePayload(oldItem, newItem) is returned the payloads is going to be empty. So it should trigger the first condition: payloads.isEmpty().

However, the getChangePayload function returns Any?, and we want a Bundle object, it’s a good practice to also check this use case. This is why you’ve got both conditions here.

I noticed that the bind (full binding) method is not guaranteed to be called during scroll thus click listener is outdated when put inside that function of the ViewHolder. I need to move it inside the onBindViewholder itself so that it gets updated while being scrolled. It seems when being scrolled either bind or update will be trigger.

I want to understand the first onBindViewHolder part where we pass emptyList(). Can you further explain as well why we pass emptyList() in the first onBindViewHolder method?

Hello archeremiya,

I believe you’re describing this scenario, right:

override fun onBindViewHolder(holder: ItemViewHolder, pos: Int) {
  onBindViewHolder(holder, pos, emptyList())
}

onBindViewHolder is called when the first data is added to the list. Since there are no other data to compare your data, the payload is going to be empty.

override fun onBindViewHolder(viewHolder: ItemViewHolder, pos: Int, payload: List<Any>) 

Since it’s necessary to override both onBindViewHolder’s, to avoid duplicating the code, I’m calling the onBindViewHolder with an empty list. All the logic is handled in this second function.

This sample already handles the onClickEvent. If you need to migrate it to the adapter, you need to add its logic when an item is set, otherwise, you might get the listener from a different element in the list.

1 Like

Thanks a lot for taking the time to explain it!

1 Like

Hi again, I think we can remove the checking in getChangePayload since it is only called when areItemsTheSame is true and areContentsTheSame is false. The done property in data class Item is in primary constructor and the sample checking in DiffUtil’s areItemsTheSame is utilizing default generated equals. It means (oldItem.done == newItem.done) is always false in getChangePayload unless there is other reason that trigger item’s property changed.

1 Like

Hello archeremiya,

That’s true - good suggestion :]. The reason why I have added those verifications is more of a security for the scenario where another developer changes the object without realizing that it might break something in another place.

1 Like