How To Use DiffUtil Class With RecyclerView In Android

Introduction

Hi friends!! In this article, we will learn about DiffUtil Class and how we can use with RecyclerView in Android. When working with a RecyclerView, the most common way to update its contents is by using an adapter. The adapter provides the views for the data items and handles the binding of data to these views. However, when the dataset changes (items are added, removed, or modified), the adapter needs to reflect these changes in the UI. We can use notifyDataSetChanged() and it is really good when we have small data but when we have a large amount of data then notifyDataSetChanged() does not work well that's why we can use Diffutil class.

Prerequisite

  • Having a basic knowledge of Android 
  • Having the latest version of android studio
  • Having a basic knowledge of RecyclerView 

What is DiffUtil Class?

According to Android official docs:-

"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". So using this class we can handle updates and changes in the dataset of the RecyclerView adapter efficiently. Let's understand this concept in a practical way - 

Example

We are going to make an app that has a list of employees and we can sort employees by their name and their role.

Let's Start With Android Studio

Step 1. Create A New Project

Step 2. Create a new model class

Employee.java

public class Employee {

    public int id;
    public String name;
    public String role;

    public Employee(final int id, final String name, final String role) {
        this.id = id;
        this.name = name;
        this.role = role;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getRole() {
        return role;
    }
}

Step 3. Create a new class for dummy data

DummyEmployeeDataUtils.java

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class DummyEmployeeDataUtils {
    public static List<Employee> getEmployeeListSortedByName() {
        final List<Employee> employeeList = getEmployeeList();

        Collections.sort(employeeList, new Comparator<Employee>() {
            @Override
            public int compare(Employee a1, Employee a2) {
                return a1.getName().compareTo(a2.getName());
            }
        });

        return employeeList;
    }

    public static List<Employee> getEmployeeListSortedByRole() {
        final List<Employee> employeeList = getEmployeeList();

        Collections.sort(employeeList, new Comparator<Employee>() {
            @Override
            public int compare(Employee a1, Employee a2) {
                return a2.getRole().compareTo(a1.getRole());
            }
        });
        return employeeList;
    }

    private static List<Employee> getEmployeeList() {
        final List<Employee> employees = new ArrayList<>();
        employees.add(new Employee(1, "Employee 1", "Developer"));
        employees.add(new Employee(2, "Employee 2", "Tester"));
        employees.add(new Employee(3, "Employee 3", "Support"));
        employees.add(new Employee(4, "Employee 4", "Sales Manager"));
        employees.add(new Employee(5, "Employee 5", "Manager"));
        employees.add(new Employee(6, "Employee 6", "Team lead"));
        employees.add(new Employee(7, "Employee 7", "Scrum Master"));
        employees.add(new Employee(8, "Employee 8", "Sr. Tester"));
        employees.add(new Employee(9, "Employee 9", "Sr. Developer"));
        employees.add(new Employee(10, "Employee 10", "Developer"));
        return employees;
    }

}

Here we manage a list of employee data and define some essential methods, such as:

  • getEmployeeList() Method: This method creates and returns a list of Employee objects. Each Employee object has an ID, a name, and a role.

  • getEmployeeListSortedByName() Method: This method generates a list of employee data using the getEmployeeList() method. It sorts the list of employees based on their names in ascending order using the Collections.sort() method.

  • getEmployeeListSortedByRole() Method: This method generates a list of employee data using the getEmployeeList() method. It sorts the list of employees based on their roles in descending order using the Collections.sort() method.

The above method is used in other classes for accessing the employee list data.

Step 4. Create a new class  

EmployeeDiffCallback.java

import androidx.recyclerview.widget.DiffUtil;
import java.util.List;

public class EmployeeDiffCallback extends DiffUtil.Callback {

    private final List<Employee> mOldEmployeeList;
    private final List<Employee> mNewEmployeeList;
    public EmployeeDiffCallback(List<Employee> oldEmployeeList, List<Employee> newEmployeeList) {
        this.mOldEmployeeList = oldEmployeeList;
        this.mNewEmployeeList = newEmployeeList;
    }
    @Override
    public int getOldListSize() {
        return mOldEmployeeList.size();
    }
    @Override
    public int getNewListSize() {
        return mNewEmployeeList.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return mOldEmployeeList.get(oldItemPosition).getId() == mNewEmployeeList.get(
                newItemPosition).getId();
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        final Employee oldEmployee = mOldEmployeeList.get(oldItemPosition);
        final Employee newEmployee = mNewEmployeeList.get(newItemPosition);

        return oldEmployee.getName().equals(newEmployee.getName());
    }
}

 This class extends DiffUtil.Callback and used to determine differences between two lists of employee data to efficiently update a RecyclerView adapter. Here we pass two lists using the constructor and It calculates differences between the old and new lists based on name and role. This helps in minimizing UI updates and providing smoother animations when items are added, removed, or changed in the RecyclerView. 

Some Important methods which are used in this class are as follows:

  • areItemsTheSame() Method: This method checks if the item at a specific position in the old list is the same as the item at the same position in the new list. It compares the Ids of the employees to determine if they are the same.
  • areContentsTheSame() Method: This method checks if the contents of the items at a specific position in the old and new lists are the same. It compares the names of the employees to determine if they are the same.

Step 5. Create a list_item for RecyclerView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content">

    <TextView
        android:id="@+id/employee_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:textSize="18sp"/>

    <TextView
        android:id="@+id/employee_role"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:textSize="18sp"/>

</LinearLayout>

This .xml file is used to define the appearance of each individual item in a RecyclerView when using an adapter.

Step 6. Create an adapter class

EmployeeRecyclerViewAdapter.java

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;

public class EmployeeRecyclerViewAdapter extends RecyclerView.Adapter<EmployeeRecyclerViewAdapter.ViewHolder> {

    private List<Employee> mEmployees = new ArrayList<>();

    public EmployeeRecyclerViewAdapter(List<Employee> employeeList) {
        this.mEmployees.addAll(employeeList);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        final View view = inflater.inflate(R.layout.list_item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        final Employee employee = mEmployees.get(position);
        holder.name.setText(employee.getName());
        holder.role.setText(employee.getRole());
    }

    public void updateEmployeeListItems(List<Employee> employees) {
        final EmployeeDiffCallback diffCallback = new EmployeeDiffCallback(this.mEmployees, employees);
        final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);

        this.mEmployees.clear();
        this.mEmployees.addAll(employees);
        diffResult.dispatchUpdatesTo(this);
    }

    @Override
    public int getItemCount() {
        return mEmployees.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        private final TextView role;
        private final TextView name;

        public ViewHolder(View itemView) {
            super(itemView);
            name = (TextView) itemView.findViewById(R.id.employee_name);
            role = (TextView) itemView.findViewById(R.id.employee_role);
        }
    }
}

This adapter class is used to display a list of employees using a RecyclerView. The adapter can update the list of employees and automatically refresh the UI using DiffUtil class, which helps to show changes in a smooth way. The updateEmployeeListItems() method uses the DiffUtil class and Updates the list of employees with new data. It calculates the difference between the old and new employee lists using DiffUtil. It clears the current employee list and adds the new list, and notifies the adapter about the changes to update the UI.

Step 7. Create a menu XML file

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/sort_by_name"
        android:title="@string/sort_by_name"/>

    <item
        android:id="@+id/sort_by_role"
        android:title="@string/sort_by_role"/>
</menu>

This .xml layout file is used for creating action bar menu items.

Step 8. Edit your activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="MainActivity"/>

Go to activity_main.xml and change the existing code with the above code. Here we take a RecyclerView to display a scrollable list.

Step 9. Edit your MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    private EmployeeRecyclerViewAdapter mRecyclerViewAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRecyclerViewAdapter = new EmployeeRecyclerViewAdapter(
                DummyEmployeeDataUtils.getEmployeeListSortedByRole());
        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(mRecyclerViewAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.sort_menu, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.sort_by_name:
                mRecyclerViewAdapter.updateEmployeeListItems(
                        DummyEmployeeDataUtils.getEmployeeListSortedByName());
                return true;
            case R.id.sort_by_role:
                mRecyclerViewAdapter.updateEmployeeListItems(
                        DummyEmployeeDataUtils.getEmployeeListSortedByRole());
                return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Here we initialize RecyclerView, which displays the list of employees. The user can select sorting options from the menu to arrange the employee list by name or role. we have overridden the onCreateOptionsMenu() method for create options in the app menu. The  onOptionsItemSelected() method is overridden to handle actions when a menu item is selected.

Output

 

Conclusion

In this article, we have seen how to use DiffUtil class in RecyclerView in Android. Thanks for reading, and hope you like it. If you have any suggestions or queries about this article, please share your thoughts. You can read my other articles by clicking here.

Happy learning, friends!


Similar Articles