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

风流意气都作罢 提交于 2019-12-22 10:32:19

问题


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?


回答1:


That function will not get called because ListAdapter won't consider it as another list, since it has all the same items only the order got changed.

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

So to solve this, you need to call this function with null first, then immediately call with the order changed list.

submitList(null);
submitList(orderChangedList);



回答2:


Instead of

submitList(mySameOldListThatIModified)

You have to send 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 calls if (newList != this.mList) both newList and mList are referring to the same object, 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.toList() // Unintuitive way to copy a list
newList.first().isFavourite = false // Do whatever modifications you want
submitList(newList)



回答3:


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.



来源:https://stackoverflow.com/questions/55263384/listadapter-not-refreshing-recyclerview-if-i-submit-the-same-list-with-different

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!