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

后端 未结 5 1783
挽巷
挽巷 2021-01-12 06:57

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

相关标签:
5条回答
  • 2021-01-12 07:33

    Just call listAdapter.notifyDataSetChanged() and the ListAdapter will redraw the list based on submitted values.

    0 讨论(0)
  • 2021-01-12 07:35

    To add to Carson's answer, which is a better way to do it, you can maintain the benefits of submitList as follows in Kotlin:

    submitList(oldList.toList().toMutableList().let {
         it[index] = it[index].copy(property = newvalue) // To update a property on an item
         it.add(newItem) // To add a new item
         it.removeAt[index] // To remove an item
         // and so on....
         it
    })
    
    0 讨论(0)
  • 2021-01-12 07:37

    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.toList() // Unintuitive way to copy a list
    newList.first() = newList.first().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.

    0 讨论(0)
  • 2021-01-12 07:44

    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);
    
    0 讨论(0)
  • 2021-01-12 07:44

    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.

    0 讨论(0)
提交回复
热议问题