Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListAdapter not refreshing RecyclerView if I submit the same list with different item order

I am using a RecyclerView with ListAdapter (which uses AsyncListDiffer to calculate and animate changes when list is replaced).

The problem is that if I submit() some list, then re-order that list, and submit() again, nothing happens.

How do I force ListAdapter to evaluate this new list, even though it is "the same" (but order has changed)?

New findings:

I checked source code of submitList() and in the beggining there is a check:

public void submitList(@Nullable final List<T> newList) {
        final int runGeneration = ++this.mMaxScheduledGeneration;
        if (newList != this.mList) {

I think this is the problem. But how to get past it? I mean, surely the developers thought about submiting a different ordered list?

like image 508
c0dehunter Avatar asked Mar 20 '19 14:03

c0dehunter


People also ask

Are items same Vs are contents same?

areItemsTheSame(T, T) is called to see if two objects are the same. If not there may be a need to add/delete the item. areContentsTheSame is called only when the areItemsTheSame(T, T) return true. In this case, the item was available previously, but the content is changed, so the respective change should be displayed.

How do you update one item in RecyclerView?

Update single item Change the "Sheep" item so that it says "I like sheep." String newValue = "I like sheep."; int updateIndex = 3; data. set(updateIndex, newValue); adapter. notifyItemChanged(updateIndex);

How do I stop refreshing RecyclerView data scroll to top position android?

Make a setDataList method in your adapter class. And set your updated list to adapter list. And then every time of calling API set that list to setDataList and call adapter. notifyDataSetChanged() method of your adapter class.


2 Answers

Instead of

submitList(mySameOldListThatIModified)

You have to submit a new list like this:

ArrayList newList = new ArrayList(oldList);
newList.add(somethingNew); // Or sort or do whatever you want
submitList(newList);

It's kind of a problem with the API. We would expect ListAdapter to keep a copy of the list, but it doesn't, probably for memory reasons. When you change your old list, you are actually changing the same list that ListAdapter has stored. When ListAdapter checks if (newList != this.mList) both newList and mList are referring to the same list instance, so no matter what you have changed on that list, it will equal itself, and ignore your update.

In kotlin you can create a new list via:

val newList = oldList.toMutableList() // Unintuitive way to copy a list
newList[0] = newList[0].copy(isFavourite = false) // Do whatever modifications you want
submitList(newList)

Note that you cannot do this:

newList.first().isFavourite = false

because that will also change the first item in your old list, and again ListAdapter won't see a difference between the first item in your old list and the first item in your new list. I would recommend that all items in your list have val properties exclusively, to avoid this problem.

like image 99
Carson Holzheimer Avatar answered Sep 19 '22 18:09

Carson Holzheimer


It defeats ListAdapter's purpose for automatically calculating and animating list changes when you call these lines consecutively:

submitList(null);
submitList(orderChangedList);

Meaning, you only cleared (null) the ListAdapter's currentList and then submitted ( .submitList()) a new List. Thus, no corresponding animation will be seen in this case but only a refresh of the entire RecyclerView.

Solution is to implement the .submitList( List<T> list) method inside your ListAdapter as follows:

public void submitList(@Nullable List<T> list) {
    mDiffer.submitList(list != null ? new ArrayList<>(list) : null);
}

This way you allow the ListAdapter to retain its currentList and have it "diffed" with the newList, thereby the calculated animations, as opposed to "diffing" with a null.

Note: However, no update animation will happen, if, of course, the newList contains the same items in the same order as the originalList.

like image 37
aLL Avatar answered Sep 20 '22 18:09

aLL