Reputation: 2781
I used notifyDataSetChanged
in in my recycleriew
. like this:
private void setList(List<Article> articles) {
mainList.addAll(articles);
notifyDataSetChanged();
}
But I want to use diffUtill
in my recycleriew
. I created my own diffUtill
like this:
public class ArticleListDiffTool extends DiffUtil.Callback {
List<Article> oldList;
List<Article> newList;
private static final String TAG = "ArticleListDiffTool";
public ArticleListDiffTool(List<Article> oldList, List<Article> newList) {
this.oldList = oldList;
this.newList = newList;
Log.d(TAG, "ArticleListDiffTool: " + this.oldList.size() + "\n" + this.newList.size());
}
@Override
public int getOldListSize() {
return oldList.size();
}
@Override
public int getNewListSize() {
return newList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).getId() .equals( newList.get(newItemPosition).getId());
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).equals(newList.get(newItemPosition));
}
@Nullable
@Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
//you can return particular field for changed item.
return super.getChangePayload(oldItemPosition, newItemPosition);
}
}
And I use it in my adapter :
private void setList(List articles) {
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new ArticleListDiffTool(this.mainList, articles),true);
mainList.addAll(articles);
diffResult.dispatchUpdatesTo(this);
}
I want to add new data to my old list. But when new data received, the recyclerView
will be scrolled to the top of the list.
But I want to recyclerView be in its user state and new data add to the rest of the old list.
Upvotes: 1
Views: 1719
Reputation: 2781
I Found the problem after a few hours.
I every time that wants to update my recyclerView send received data to my adapter And DiffUtil goes to compare my old list with received new parts and because of that (completely new items) DiffUtil decides to refresh whole recyclerView list.
Solution:
Now I get the current list from the recyclerView
adapter and use addAll
to insert new items that received from the server, then I pass this complete list to the adapter.
Now DiffUtil can compare diffrent between my old and new lists and recyclerView will be stay at it's current position.
Upvotes: 1
Reputation: 34542
RecylcerView updates knows nothing about your views. When you call notifyDataSetChanged
it tries to determine which views moved, or were replaced. I don't see you using setHasStableIds
so when calling notifyDataSetChanged
it will assume all of the content was replaced. It will jump to position 0
and be done with it. When you use setHasStableIds
it will check the ids of the visible items and update the content in them. It will stop jumping around.
Now you also show that you are using DiffUtil
. This is great! When you're not working with setHasStableIds
this is the way to properly tell the recyclerView about what changed.
The problem you are facing is that you're using both. Either move to long
ids and let the recyclerview do the diffing itself, or use DiffUtil and remove the call to notifyDataSetChanged
. Either variant should work.
Upvotes: 4
Reputation:
If you add new items at the end of the recyclerview, before you add the data, store the 1st visible item in recyclerview:
int position = ((LinearLayoutManager) recyclerView.GetLayoutManager()).findFirstVisibleItemPosition();
and after you make all the changes and call notifyDatasetChanged()
scroll to position
:
recyclerView.scrollToPosition(position);
Upvotes: 1