Site icon Howtodoandroid

Update Android Recyclerview Using Diffutil

Update-Android-Recyclerview-Using-Diffutil

If you are an Android Developer, I am sure you’ve used RecyclerView in your android application. In this tutorial, I am going to explain how to update the RecyclerView with DiffUtils. What exactly is RecyclerView? RecyclerView is a more adaptable and efficient version of ListView. It is a container for displaying a larger data set of views that can be recycled and scrolled very quickly.

To learn more about recyclerview, check Recyclerview Android.

What is Recyclerview Diffutil?

There is no way for the RecyclerView to know what the real changes are if notifyDataSetChanged() is used. As a result, all visible views are rebuilt. This is an extremely costly surgery. During this procedure, a new instance of the adapter is generated. As a result, the process is highly time-consuming.

To address this, Android introduced DiffUtils as part of its support library.

DiffUtil is a utility class that can calculate the difference between two lists and output a list of update operations that converts the first list into the second one. It can be used to calculate updates for a RecyclerView Adapter.

Diffutils is based on Eugene Myers’ algorithm.

DiffUtil uses the following methods of the RecyclerViewAdapter:

notifyItemMoved()
notifyItemRangeChanged()
notifyItemRangeInserted()
notifyItemRangeRemoved()
These are less costlier than notifyDataSetChanged since they work on individual operations.

What are the Benefits of using DiffUtil?

Here is the performance chart which illustrates that using DiffUtil is better in the case of RecyclerView. These results are based on Nexus 5X with M-

Creating a DiffUtil class

To create a Recyclerview Diffutil class, Need to extend the Diffutil.CallBack class.

class UserDiffUtilCallback(private val oldList: List<Users>, private val newList: List<Users>) : DiffUtil.Callback() { override fun getOldListSize(): Int { return oldList.size } override fun getNewListSize(): Int { return newList.size } override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return oldList[oldItemPosition].id == newList[newItemPosition].id } override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return when { oldList[oldItemPosition].id == newList[newItemPosition].id -> true oldList[oldItemPosition].name == newList[newItemPosition].name -> true else -> false } } override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { return super.getChangePayload(oldItemPosition, newItemPosition) } }
Code language: HTML, XML (xml)

Diffutil.CallBack the class has the following methods that need to be implemented:

Using DiffUtil in RecyclerView Adapter

I have explained about the Recyclerview In another tutorial, So I am directly moving on to the setup of the DiffUtil on the recyclerview adapter.

Now, to make use of this, we replace the set data in Adapter,

fun setUserList(updatedUserList: List<Users>) { val diffResult = DiffUtil.calculateDiff(UserDiffUtilCallback(userList, updatedUserList)) userList.clear() userList.addAll(updatedUserList) diffResult.dispatchUpdatesTo(this) }
Code language: HTML, XML (xml)

Here, we pass both the old and new lists in UserDiffUtilCallback and then we calculate the difference. After we know the difference, we update the user list and notify the adapter via dispatchUpdatesTo.

dispatchUpdatesTo(this) invokes the adapter and informs it about the views to be updated. Next, we copy the new Data list to the data.

Let’s see the Recyclerview diff util example code,

Recyclerview DiffUtil Example

MainActivity.kt

class MainActivity : AppCompatActivity() { lateinit var recyclerView: RecyclerView val users = listOf<Users>( Users(1, "User1", "location1", "image"), Users(2, "User2", "location2", "image"), Users(3,"User3","location3","image"), Users(4,"User4","location4","image"), Users(5,"User5","location5","image") ) val userAdapter = UserAdapter(users.toMutableList()) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) recyclerView = findViewById(R.id.recyclerview) recyclerView.adapter = userAdapter val btn = findViewById<Button>(R.id.btnSortDescending) btn.setOnClickListener { val sortedList = users.sortedByDescending { it.id } userAdapter.setUserList(sortedList) } val btnAscending = findViewById<Button>(R.id.btnAscending) btnAscending.setOnClickListener { val sortedList = users.sortedBy { it.id } userAdapter.setUserList(sortedList) } } }
Code language: HTML, XML (xml)

Model.kt

data class Users(val id: Int, val name: String, val address: String, val image: String)

UserAdapter.kt

class UserAdapter(private val userList: MutableList<Users>): RecyclerView.Adapter<UserAdapter.UserViewHolder>() { fun setUserList(updatedUserList: List<Users>) { val diffResult = DiffUtil.calculateDiff(UserDiffUtilCallback(userList, updatedUserList)) userList.clear() userList.addAll(updatedUserList) diffResult.dispatchUpdatesTo(this) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.adapter_user, parent, false) return UserViewHolder(view) } override fun onBindViewHolder(holder: UserViewHolder, position: Int) { val user = userList[position] holder.username.text = user.name holder.address.text = user.address } override fun getItemCount(): Int { return userList.size } inner class UserViewHolder(view: View): RecyclerView.ViewHolder(view) { val username: AppCompatTextView = view.findViewById(R.id.username) val address: AppCompatTextView = view.findViewById(R.id.address) } }
Code language: HTML, XML (xml)

UserDiffUtilCallback.kt

class UserDiffUtilCallback(private val oldList: List<Users>, private val newList: List<Users>) : DiffUtil.Callback() { override fun getOldListSize(): Int { return oldList.size } override fun getNewListSize(): Int { return newList.size } override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return oldList[oldItemPosition].id == newList[newItemPosition].id } override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return when { oldList[oldItemPosition].id == newList[newItemPosition].id -> true oldList[oldItemPosition].name == newList[newItemPosition].name -> true else -> false } } override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { return super.getChangePayload(oldItemPosition, newItemPosition) } }
Code language: HTML, XML (xml)

demo:

This brings an end to this tutorial. You can download the project from GitHub.

Exit mobile version