16

我正在使用RecyclerViewwith ListAdapter(它使用AsyncListDiffer在替换列表时计算和动画更改)。

问题是,如果我submit()列出了一些列表,然后重新排序该列表,submit()同样,什么也没有发生。

我如何强制ListAdapter评估这个新列表,即使它是“相同的”(但顺序已经改变)?

新发现:

我检查了submitList()的源代码,并在开始时进行了检查:

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

我认为这是问题所在。但是如何克服呢?我的意思是,开发人员肯定考虑过提交不同的有序列表吗?

4

8 回答 8

21

代替

submitList(mySameOldListThatIModified)

您必须像这样提交一个新列表:

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

这是API的一个问题。我们希望 ListAdapter 保留列表的副本,但它没有,可能是出于内存原因。当您更改旧列表时,实际上是在更改 ListAdapter 存储的同一个列表。当 ListAdapter 检查if (newList != this.mList) 两者newListmList引用同一个列表实例时,因此无论您对该列表进行了哪些更改,它都将等于自身,并忽略您的更新。

在 kotlin 中,您可以通过以下方式创建新列表:

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

请注意,您不能这样做:

newList.first().isFavourite = false

因为这也会更改旧列表中的第一项,并且ListAdapter不会再看到旧列表中的第一项和新列表中的第一项之间的差异。我建议您列表中的所有项目都val具有专有属性,以避免此问题。

于 2019-09-09T05:44:02.410 回答
2

当您连续调用这些行时,它破坏了 ListAdapter自动计算和动画列表更改的目的:

submitList(null);
submitList(orderChangedList);

意思是,您只清除 ( null) ListAdapter 的 currentList,然后提交 ( .submitList()) 一个新列表。因此,在这种情况下不会看到相应的动画,而只会看到整个 RecyclerView 的刷新。

解决方案是在 ListAdapter 中实现该.submitList( List<T> list)方法,如下所示:

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

这样,您允许 ListAdapter 保留其 currentList 并使其与 newList “差异”,从而计算动画,而不是与null.

注意:当然,如果 newList 包含与 originalList 相同顺序的相同项目,则不会发生更新动画。

于 2019-03-21T12:20:10.083 回答
1

要添加到 Carson 的答案,这是一种更好的方法,您可以submitList在 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
})
于 2020-06-08T00:43:16.947 回答
1

如果您有 enable setHasFixedSize(true),请删除此行。

“如果 RecyclerView 可以提前知道 RecyclerView 的大小不受适配器内容的影响,RecyclerView 可以进行多项优化......”

于 2021-04-06T00:26:28.097 回答
1

问题是提交的新列表未呈现。

androidx.recyclerview:recyclerview:1.2.0-beta02

临时解决方案是在新列表提交后平滑滚动到任何位置,我这样做到顶部。

movieListAdapter.submitList(list) {
    binding.recycler.smoothScrollToPosition(0)
}
于 2021-03-11T10:17:43.590 回答
0

我遇到了类似的问题,但不正确的渲染是由 setHasFixedSize(true) 和 android:layout_height="wrap_content" 的组合引起的。第一次为适配器提供了一个空列表,因此高度从未更新并且为 0。无论如何,这解决了我的问题。其他人可能有同样的问题,并会认为这是适配器的问题。

android recyclerview listadapter 示例,RecyclerView ListAdapter。ListAdapter 是一个显示列表的 RecyclerView 适配器。这在 RecyclerView 27.1+ 中可用,如果您无法扩展适配器,相同的功能也存在于 AsyncListDiffer 类中。ListAdapter 可帮助您使用随时间改变内容的 RecyclerView。usersList.observe(this, list -> adapter.submitList(list)); recyclerView.setAdapter(​适配器); } } 类 UserAdapter 扩展 ListAdapter<User,

这个人的所有学分: https ://www.xspdf.com/help/50031492.html

于 2021-02-05T03:32:12.437 回答
0

该函数不会被调用,因为ListAdapter它不会将其视为另一个列表,因为它具有所有相同的项目,只是顺序发生了变化。

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

所以要解决这个问题,你需要先调用这个函数null,然后立即调用顺序更改列表。

submitList(null);
submitList(orderChangedList);
于 2019-03-20T15:07:06.097 回答
-3

只需调用listAdapter.notifyDataSetChanged()ListAdapter它将根据提交的值重新绘制列表。

于 2020-06-26T12:54:54.510 回答