DiffUtil in RecyclerView

Why do you need DiffUtil in RecyclerView?

Let’s take an example that your app is showing around 100 items in RecyclerView. After 40-50 seconds, new data came from the server and you need to show updated data. In that new data, some new items are added, some items are updated and some items are removed. You don’t know. Still, you need to show these updated items to the user.

A simple solution is that just remove all items from RecyclerView and add all new items and tell the adapter to update all items. Something like this:

fun setData(updateList: List<User>) {    
        list.clear()
        list.addAll(newList)

        notifyDataSetChanged()
}

However, removing all items and later adding them is a very costly operation to perform. It may impact app performance as well.

So, another solution is that you need to take an old list and a new list, compare each element and need to figure out which item is added, removed and updated. And after that, prepare all operations which you need to tell adapter to perform on RecyclerView like add, update or delete.

But, it is not feasible for every developer to write code for the above mechanism. So, that’s where DiffUtil comes into the picture. Let’s see what it is.

What is DiffUtil?

DiffUtil is a utility class that calculates the difference between two lists and outputs a list of update operations that converts the first list into the second one.

Google

In simple words, it takes an old list and a new list and produces different operations like add the item at xth position or remove the item at yth position or update items to this position range from a to b. And gives these operations to the adapter to show updated data.

Internally, DiffUtil uses Myers’s difference algorithm to do this magic. Now, let’s see how we can implement it.

How can we implement DiffUtil in RecyclerView?

When it comes to implement, it is really really easy. In only two steps, we can implement this. Let’s see the first step:

class GroceryItem(val id: Int, val price: Int, val name: String)

private class GroceryItemDiffUtil(
    val oldData: List<GroceryItem>,
    val newData: List<GroceryItem>
) : DiffUtil.Callback() {

    override fun getOldListSize() = oldData.size

    override fun getNewListSize() = newData.size

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldData[oldItemPosition].id == newData[newItemPosition].id
    }

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val lhs = oldData[oldItemPosition]
        val rhs = newData[newItemPosition]

        return lhs.price == rhs.price && lhs.name == rhs.name
    }
}

Here, we want to get the difference between the two lists. For that, you need to create a class which will implement DiffUtil.Callback interface which has the following methods to implement:

getOldListSize(): Gives the size of the old list

getNewListSize(): Gives the size of the new list

areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Checks if two objects are representing the same item. Here, it checks both grocery items are the same item via id.

areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Checks if two objects have the same content. And this method invokes only if areItemsTheSame returns true.

And the final step is to use above class to show the updated data in RecyclerView:

class GroceryItemAdapter(private val context: Context) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private val groceryItems = mutableListOf<GroceryItem>()

    fun addData(updatedGroceryItems: List<GroceryItem>) {
        val diffResult = DiffUtil.calculateDiff(GroceryItemDiffUtil(groceryItems, updatedGroceryItems))

        groceryItems.clear()
        groceryItems.addAll(updatedGroceryItems)
        diffResult.dispatchUpdatesTo(this)
    }
}

Here, DiffUtil calculates the difference via GroceryItemDiffUtil and gives the result named diffResult which gives the events to adapter to show updated data. Here, an important point to note is that we have removed the notifyDataSetChanged() method.

That’s it in DiffUtil! Thank you very much for reading. I hope you liked the article. Feel free to share any feedback.

Thanks for reading! Please share this article with others to spread knowledge.

Leave a Reply

Your email address will not be published. Required fields are marked *