Skip to content

Instantly share code, notes, and snippets.

@avipars
Created February 27, 2021 20:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save avipars/29ff1de5b2d6d19df223fbe441e424ee to your computer and use it in GitHub Desktop.
Save avipars/29ff1de5b2d6d19df223fbe441e424ee to your computer and use it in GitHub Desktop.
Android Medium Articles
Updating data in an Android RecyclerView
Suragch
Suragch
Dec 22, 2018·4 min read
This is a repost of an answer I wrote on Stack Overflow.
There are two main things that I find helpful when exploring a new API: seeing examples (especially ones with pictures) and just trying out all the possibilities. This post will hopefully help you with that as you are learning how to update the adapter data in an Android RecyclerView. If you need help setting up the RecyclerView itself, then see this post or scroll down to the Code section below.
Overview
The process of modifying the adapter data includes two main steps every time:
Update the data set
Notify the adapter of the change
The following examples will show how to do that.
Insert single item
Add “Pig” at index 2.
Image for post
String item = "Pig";
int insertIndex = 2;
data.add(insertIndex, item);
adapter.notifyItemInserted(insertIndex);
Insert multiple items
Insert three more animals at index 2.
Image for post
ArrayList<String> items = new ArrayList<>();
items.add("Pig");
items.add("Chicken");
items.add("Dog");
int insertIndex = 2;
data.addAll(insertIndex, items);
adapter.notifyItemRangeInserted(insertIndex, items.size());
Remove single item
Remove “Pig” from the list.
Image for post
int removeIndex = 2;
data.remove(removeIndex);
adapter.notifyItemRemoved(removeIndex);
Remove multiple items
Remove “Camel” and “Sheep” from the list.
Image for post
int startIndex = 2; // inclusive
int endIndex = 4; // exclusive
int count = endIndex - startIndex; // 2 items will be removed
data.subList(startIndex, endIndex).clear();
adapter.notifyItemRangeRemoved(startIndex, count);
Remove all items
Clear the whole list.
Image for post
data.clear();
adapter.notifyDataSetChanged();
Replace old list with new list
Clear the old list then add a new one.
Image for post
// clear old list
data.clear();
// add new list
ArrayList<String> newList = new ArrayList<>();
newList.add("Lion");
newList.add("Wolf");
newList.add("Bear");
data.addAll(newList);
// notify adapter
adapter.notifyDataSetChanged();
The adapter has a reference to data, so it is important that I didn't set data to a new object. Instead I cleared the old items from data and then added the new ones.
Update single item
Change the “Sheep” item so that it says “I like sheep.”
Image for post
String newValue = "I like sheep.";
int updateIndex = 3;
data.set(updateIndex, newValue);
adapter.notifyItemChanged(updateIndex);
Move single item
Move “Sheep” from position 3 to position 1.
Image for post
int fromPosition = 3;
int toPosition = 1;
// update data array
String item = data.get(fromPosition);
data.remove(fromPosition);
data.add(toPosition, item);
// notify adapter
adapter.notifyItemMoved(fromPosition, toPosition);
Code
Here is the project code for your reference. The RecyclerView Adapter code can be found at this answer.
MainActivity.java
public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener {
List<String> data;
MyRecyclerViewAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// data to populate the RecyclerView with
data = new ArrayList<>();
data.add("Horse");
data.add("Cow");
data.add("Camel");
data.add("Sheep");
data.add("Goat");
// set up the RecyclerView
RecyclerView recyclerView = findViewById(R.id.rvAnimals);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
layoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);
adapter = new MyRecyclerViewAdapter(this, data);
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
}
@Override
public void onItemClick(View view, int position) {
Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
}
public void onButtonClick(View view) {
insertSingleItem();
}
private void insertSingleItem() {
String item = "Pig";
int insertIndex = 2;
data.add(insertIndex, item);
adapter.notifyItemInserted(insertIndex);
}
private void insertMultipleItems() {
ArrayList<String> items = new ArrayList<>();
items.add("Pig");
items.add("Chicken");
items.add("Dog");
int insertIndex = 2;
data.addAll(insertIndex, items);
adapter.notifyItemRangeInserted(insertIndex, items.size());
}
private void removeSingleItem() {
int removeIndex = 2;
data.remove(removeIndex);
adapter.notifyItemRemoved(removeIndex);
}
private void removeMultipleItems() {
int startIndex = 2; // inclusive
int endIndex = 4; // exclusive
int count = endIndex - startIndex; // 2 items will be removed
data.subList(startIndex, endIndex).clear();
adapter.notifyItemRangeRemoved(startIndex, count);
}
private void removeAllItems() {
data.clear();
adapter.notifyDataSetChanged();
}
private void replaceOldListWithNewList() {
// clear old list
data.clear();
// add new list
ArrayList<String> newList = new ArrayList<>();
newList.add("Lion");
newList.add("Wolf");
newList.add("Bear");
data.addAll(newList);
// notify adapter
adapter.notifyDataSetChanged();
}
private void updateSingleItem() {
String newValue = "I like sheep.";
int updateIndex = 3;
data.set(updateIndex, newValue);
adapter.notifyItemChanged(updateIndex);
}
private void moveSingleItem() {
int fromPosition = 3;
int toPosition = 1;
// update data array
String item = data.get(fromPosition);
data.remove(fromPosition);
data.add(toPosition, item);
// notify adapter
adapter.notifyItemMoved(fromPosition, toPosition);
}
}
Notes
If you use notifyDataSetChanged(), then no animation will be performed. This can also be an expensive operation, so it is not recommended to use notifyDataSetChanged() if you are only updating a single item or a range of items.
Check out DiffUtil if you are making large or complex changes to a list.
Further study
CodePath: Using the RecyclerView
Smart way to update RecyclerView using DiffUtil
https://suragch.medium.com/updating-data-in-an-android-recyclerview-842e56adbfd8
Now say good bye to notifyDataSetChanged()…
We generally use List in any of our day to day development. It also requires to update the list data when user scrolls the list. To achieve this, we often fetch the data from server and update the newly received items.
If there is a small delay during this process it impact on the user experience so we want this to be done as soon as possible with along with less resources.
When the content of our list gets changed, we have to call notifyDataSetChanged() to get the updates but it is very costly. There are so many iterations for getting the job done in the case of notifyDataSetChanged().
Here DiffUtil class comes into picture and Android developed this utility class to handle data updates for a RecyclerView.
What is DiffUtil
As of 24.2.0, RecyclerView support library, v7 package offers really handy utility class called DiffUtil. This class finds the difference between two lists and provides the updated list as an output. This class is used to notify updates to a RecyclerView Adapter.
It uses Eugene W. Myers’s difference algorithm to calculate the minimal number of updates.
How to use?
DiffUtil.Callback is an abstract class and used as callback class by DiffUtil while calculating the difference between two lists. It has four abstract methods and one non-abstract method. You have to extend it and override all its methods-
getOldListSize()– Return the size of the old list.
getNewListSize()– Return the size of the new list.
areItemsTheSame(int oldItemPosition, int newItemPosition)– It decides whether two objects are representing same items or not.
areContentsTheSame(int oldItemPosition, int newItemPosition)– It decides whether two items have same data or not. This method is called by DiffUtil only if areItemsTheSame() returns true.
getChangePayload(int oldItemPosition, int newItemPosition)– If areItemTheSame() returns true and areContentsTheSame() returns false than DiffUtil utility calls this method to get a payload about the change.
Below are a simple Employee class which is using in the EmployeeRecyclerViewAdapter and EmployeeDiffCallback to sort the employee list.
Here is the implementation of Diff.Callback class. You can notice that getChangePayload() is not abstract method.
Once DiffUtil.Callback implementation are done, you have to update the list change in RecyclerViewAdapter as described below-
Call dispatchUpdatesTo(RecyclerView.Adapter) to dispatch the updated list. DiffResult object that is returned from diff calculation, dispatches the changes to the Adapter, and adapter will be notified about the change.
Object returned in getChangePayload() is dispatched from DiffResult using notifyItemRangeChanged(position, count, payload), upon which is called Adapter’s onBindViewHolder(… List<Object> payloads) method.
DiffUtil also uses methods of RecyclerView.Adapter to notify the Adapter to update the data set:
notifyItemMoved()
notifyItemRangeChanged()
notifyItemRangeInserted()
notifyItemRangeRemoved()
You can read more details on RecyclerView.Adapter and its method here.
Important:
If the lists are large, this operation may take significant time so you are advised to run this on a background thread, get the DiffUtil#DiffResult then apply it on the RecyclerView on the main thread. Also max size of the list can be 2²⁶ due to implementation constraints.
Performance
DiffUtil requires O(N) space to find the minimal number of addition and removal operations between the two lists. It’s expected performance is O(N + D²) where N is the total number of added and removed items and D is the length of the edit script. You can walk through the official page of Android for more performance figures.
You can find the reference implementation of above DiffUtil example on GitHub
Thanks for reading. To help others please click ❤ to recommend this article if you found it helpful.
Check out my blogger page for more interesting topics on Software development.
You can also follow me at :
https://medium.com/android-news/smart-way-to-update-recyclerview-using-diffutil-345941a160e0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment