How to Improve RecyclerView Performance in Android Using DiffUtil?
Last Updated :
23 Mar, 2021
DiffUtil class is used to improve the performance of RecyclerView. The algorithm behind DiffUtil is that it takes two lists and finds differences between the two and provides the updated list as an output. It uses Eugene W. Myers’s difference algorithm to calculate the minimal number of updates. In this article, we will see its implementations. Note that we are going to implement this project using the Kotlin language.
Step by Step Implementation
Step 1: Create a new project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.
Step 2: Add view binding dependency
Go to build.gradle(app) and the following dependency inside the android tag and click sync now.
buildFeatures {
viewBinding true
}
Step 3: Create a new model class
Create a new class Language.kt we will use data of custom generic “Language” to pass in the list that will be shown in RecyclerView.
Kotlin
class Language(
val id : Int = 0 ,
val name : String = "" ,
val exp : String = ""
)
|
Step 4: Create a new layout file and name it the single_item.xml file
Go to the single_item.xml file and refer to the following code. Below is the code for the single_item.xml file. It is the single item layout that we will use in RecyclerView.
XML
<? xml version = "1.0" encoding = "utf-8" ?>
< com.google.android.material.card.MaterialCardView
android:layout_width = "match_parent"
android:layout_marginBottom = "10dp"
android:layout_marginStart = "5dp"
android:layout_marginEnd = "5dp"
android:layout_height = "110dp" >
< androidx.constraintlayout.widget.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "match_parent" >
< ImageView
android:id = "@+id/iv_language"
android:layout_width = "80dp"
android:layout_height = "90dp"
android:layout_marginStart = "20dp"
android:layout_marginTop = "10dp"
android:scaleType = "fitCenter"
android:src = "@mipmap/ic_launcher"
app:layout_constraintLeft_toLeftOf = "parent"
app:layout_constraintTop_toTopOf = "parent" />
< TextView
android:id = "@+id/tv_lang_name"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_marginStart = "30dp"
android:layout_marginTop = "30dp"
android:text = "Language"
android:textSize = "16sp"
android:textStyle = "bold"
app:layout_constraintLeft_toRightOf = "@id/iv_language"
app:layout_constraintTop_toTopOf = "parent" />
< TextView
android:id = "@+id/tv_exp"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_marginTop = "10dp"
android:text = "Exp : 3 years"
app:layout_constraintLeft_toLeftOf = "@id/tv_lang_name"
app:layout_constraintTop_toBottomOf = "@id/tv_lang_name" />
</ androidx.constraintlayout.widget.ConstraintLayout >
</ com.google.android.material.card.MaterialCardView >
|
Step 5: Working with the activity_main.xml
Go to the activity_main.xml file and refer to the following code. Below is the code for the activity_main.xml file. It has only a single RecyclerView which we will use to show our data.
XML
<? xml version = "1.0" encoding = "utf-8" ?>
< androidx.constraintlayout.widget.ConstraintLayout
android:layout_width = "match_parent"
android:background = "#F5F8FD"
android:layout_height = "match_parent"
tools:context = ".MainActivity" >
< androidx.recyclerview.widget.RecyclerView
android:id = "@+id/rv_list"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:listitem = "@layout/single_item"
app:layoutManager = "androidx.recyclerview.widget.LinearLayoutManager" />
< com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id = "@+id/btn_new_language"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "Add New Language"
android:padding = "10dp"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintRight_toRightOf = "parent"
app:layout_constraintLeft_toLeftOf = "parent"
android:layout_marginBottom = "20dp" />
</ androidx.constraintlayout.widget.ConstraintLayout >
|
Step 6: Create a new class and name it MyDiffUtil.kt
Go to MyDiffUtil.kt file and write the following code. Comments are added for a better understanding of the code.
Kotlin
import androidx.recyclerview.widget.DiffUtil
class MyDiffUtil(
private val oldList : List<Language>,
private val newList : List<Language>
) :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 -> false
oldList[oldItemPosition].name != newList[newItemPosition].name -> false
oldList[oldItemPosition].exp != newList[newItemPosition].exp -> false
else -> true
}
}
}
|
Step 7: Working with the Adapter class
Create a new class RvAdapter.kt this will act as an Adapter class for the recycler view. Using View binding we use the generated class of the layout single_item.xml ie SingleItemBinding to add data and view in the recycler view of MainActivity.kt in our case. Comments are added before the code for better understanding.
Kotlin
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.geeksforgeeks.rvadapterviewbinding.databinding.SingleItemBinding
class RvAdapter() : RecyclerView.Adapter<RvAdapter.ViewHolder>() {
private var oldLanguageList= emptyList<Language>()
inner class ViewHolder(val binding: SingleItemBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = SingleItemBinding.inflate(LayoutInflater.from(parent.context), parent, false )
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
with(holder){
with(oldLanguageList[position]){
binding.tvLangName.text = this .name
binding.tvExp.text = this .exp
}
}
}
override fun getItemCount(): Int {
return oldLanguageList.size
}
fun setData(newLanguageList : List<Language>){
val diffUtil = MyDiffUtil(oldLanguageList , newLanguageList)
val diffResult = DiffUtil.calculateDiff(diffUtil)
oldLanguageList = newLanguageList
diffResult.dispatchUpdatesTo( this )
}
}
|
Step 8: Working with the MainActivity.kt file
Go to the MainActivity.kt file and refer to the following code. Below is the code for the MainActivity.kt file. Comments are added inside the code to understand the code in more detail.
Kotlin
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.geeksforgeeks.rvadapterviewbinding.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private var _binding : ActivityMainBinding? = null
private val binding get() = _binding!!
private val rvAdapter by lazy { RvAdapter() }
override fun onCreate(savedInstanceState: Bundle?) {
super .onCreate(savedInstanceState)
_binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.rvList.layoutManager = LinearLayoutManager( this )
binding.rvList.adapter = rvAdapter
val language1= Language( 1 , "Java" , "Exp : 3 years" )
val language2=Language( 2 , "Kotlin" , "Exp : 2 years" )
val language3=Language( 3 , "Python" , "Exp : 4 years" )
rvAdapter.setData(listOf(language1, language2, language3))
binding.btnNewLanguage.setOnClickListener {
val language4= Language( 4 , "CPP" , "Exp : 5 years" )
rvAdapter.setData(listOf(language1,language2,language3,language4))
}
}
override fun onDestroy() {
super .onDestroy()
_binding = null
}
}
|
Output:
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...