DiffUtil in RecyclerView in Android

03 Sep, 2021
Have you ever created a List in Android? What did you use to make it? ListView or RecyclerView are two types of views. If you are an Android Developer it’s sure you’ve used RecyclerView at some point. In this article, we’ll go through 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. Before we go into Diff Util, let’s have a look at the RecyclerView implementation.
Let’s make an Activity MainActivity and include the following code in the activity main.xml file:
XML
<androidx.constraintlayout.widget.ConstraintLayout  xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:tools="http://schemas.android.com/tools"  xmlns:app="http://schemas.android.com/apk/res-auto"  android:layout_width="match_parent"  android:layout_height="match_parent"  tools:context=".GeeksforGeeksActivity">    <androidx.recyclerview.widget.RecyclerView    android:layout_width="match_parent"    android:layout_height="match_parent"    android:id="@+id/gfgRecyclerView"    app:layout_constraintBottom_toBottomOf="parent"    app:layout_constraintLeft_toLeftOf="parent"    app:layout_constraintRight_toRightOf="parent"    app:layout_constraintTop_toTopOf="parent"/>  </androidx.constraintlayout.widget.ConstraintLayout>
Let’s make a data model class and a Data Source now,
Kotlin
data class GeeksCourses(val courseNumber: Int, val courseRating: Int, val courseName: String)
and the data source appears to be,
Kotlin
object geeksforGeeks {    val courseList: List<Course>        get() {            val course = ArrayList<Rating>()            course.add(Rating(1, 10, "GeeksforGeeks"))            course.add(Rating(2, 12, "Android Dev"))            course.add(Rating(3, 5, "DSA"))            return course        }}
Let’s make an adaptor now to set the list in RecyclerView.
Kotlin
class CourseAdapter : RecyclerView.Adapter<CourseAdapter.ViewHolder>() {    private val courses = ArrayList<Course>()    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {        val inflater = LayoutInflater.from(parent.context)        val view = inflater.inflate(R.layout.course_list, parent, false)        return ViewHolder(view)    }    override fun onBindViewHolder(holder: ViewHolder, position: Int) {        val Course = courses[position]        holder.name_text.text = Course.name    }    fun setData(courses: List<Course>) {       courses.clear()       courses.addAll(courses)    }    override fun getItemCount(): Int {        return courses.size    }    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {        val name_text: TextView = itemView.findViewById(R.id.name_text)    }}
What if we need to update the list with fresh information?
We’ll refer to it as,
Kotlin
adapter.setData(/** any new data on courses**/)
and make a call from MainActivity,
Kotlin
adapter.notifyDataSetChanged()
GeekTip #1: The recyclerview will be updated with the new set of data as a result of this.
But, since notifyDataSetChanged was performing the work for you, why did you require DiffUtils? Let’s talk about it.
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.
It’s a utility class that helps us to perform complex tasks easily, Eugene Myers’ algorithm is the foundation of DiffUtils.
DiffUtils is used to track changes made to the RecyclerView Adapter. DiffUtil notifies the RecyclerView of any changes to the data set using the following methods:
notifyItemMovednotifyItemRangeChangednotifyItemRangeInsertednotifyItemRangeRemoved
notifyItemMoved
notifyItemRangeChanged
notifyItemRangeInserted
notifyItemRangeRemoved
These techniques are significantly more efficient than notifyDataSetChanged(). However, in order for DiffUtils to function in the project, we must give information about the old and new lists. DiffUtil is used for this. Request a callback. We’ll make a class.
Kotlin
class CoursesCallback(private val oldList: List<Course>, private val newList: List<Course>) : DiffUtil.Callback() {    override fun getCourseNew(): Int = oldList.size    override fun getNewListSize(): Int = newList.size    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {        return oldList[oldItemPosition].courseNumber=== newList.get(newItemPosition).rateIndex    }    override fun areContentsTheSame(oldCourse: Int, newPosition: Int): Boolean {        val (_, value, name) = oldList[oldCourse]        val (_, value1, name1) = newList[newPosition]        return name == name1 && value == value1    }    @Nullable    override fun geeksPayload(oldCourse: Int, newPosition: Int): Any? {        return super.geeksPayload(oldCourse, newPosition)    }}
Here,
getOldCourse(): This function returns the length of the old list.
getNewCourse(): Returns the new list’s size.
areItemsTheSame(oldPosition:Int, newPosition:Int): Called by the DiffUtil to determine whether two objects in the old and new lists represent the same Item.
areContentsTheSame(oldPosition:Int, newPosition:Int): Determines if two objects have the same data. Depending on your UI, you may modify its behavior. DiffUtil calls this function only if areItemsTheSame returns true. In our example, we’re contrasting the name and price of a certain item.
obtaingeeksPayload(oldPosition:Int, newPosition:Int): If areItemTheSame returns true and areContentsTheSame returns false, the condition is satisfied. Diff This method is called by Util to obtain a payload about the modification.
To utilize this, we change the setData function in Adapter.
Kotlin
fun setCourses(newCourse: List<Courses>) {    val diffCallback = CoursesDiffCallback(ratings, newCourse)    val diffCourses = DiffUtil.calculateDiff(diffCallback)    courses.clear()    courses.addAll(newCourse)    diffResult.dispatchUpdatesTo(this)}
The performance chart below shows that using DiffUtil is superior in the case of RecyclerView. These findings are based on the Nexus 6P with M-
100 items and 10 modifications: average: 0.39 milliseconds, median: 0.35 milliseconds3.82 ms for 100 items and 100 modifications, 3.75 ms for the median.2.09 ms for 100 items and 100 changes without movements, with a median of 2.06 ms.1000 items and 50 modifications: average: 4.67 milliseconds, median: 4.59 milliseconds1000 things and 50 changes with no moves: 3.59 ms on average, 3.50 ms on average1000 items and 200 modifications: 27.07 milliseconds, median: 26.92 milliseconds1000 items and 200 changes without moves: 13.54 milliseconds, median: 13.36 milliseconds
100 items and 10 modifications: average: 0.39 milliseconds, median: 0.35 milliseconds
3.82 ms for 100 items and 100 modifications, 3.75 ms for the median.
2.09 ms for 100 items and 100 changes without movements, with a median of 2.06 ms.
1000 items and 50 modifications: average: 4.67 milliseconds, median: 4.59 milliseconds
1000 things and 50 changes with no moves: 3.59 ms on average, 3.50 ms on average
1000 items and 200 modifications: 27.07 milliseconds, median: 26.92 milliseconds
1000 items and 200 changes without moves: 13.54 milliseconds, median: 13.36 milliseconds
Because of the specified limitation, the maximum size of the list is 226. This is how DiffUtils may be used to update the list in RecyclerView.
Blogathon-2021
Picked
Android
Blogathon
Kotlin
Android
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
How to Add Views Dynamically and Store Data in Arraylist in Android?
Android SDK and it's Components
Flutter - Custom Bottom Navigation Bar
How to Communicate Between Fragments in Android?
Retrofit with Kotlin Coroutine in Android
How to Call or Consume External API in Spring Boot?
Re-rendering Components in ReactJS
SQL Query to Insert Multiple Rows
How to Connect Python with SQL Database?
How to Import JSON Data into SQL Server?