如果我提交具有不同项目顺序的相同列表,ListAdapter 不会刷新 RecyclerView
ListAdapter not refreshing RecyclerView if I submit the same list with different item order
我正在使用 RecyclerView
和 ListAdapter (which uses AsyncListDiffer 来计算和动画更改列表时的变化)。
问题是,如果我 submit()
一些列表,然后重新排序该列表,然后再次 submit()
,没有任何反应。
如何强制 ListAdapter
评估这个新列表,即使它是 "the same"(但顺序已更改)?
新发现:
我检查了 submitList() 的源代码,在开始时有一个检查:
public void submitList(@Nullable final List<T> newList) {
final int runGeneration = ++this.mMaxScheduledGeneration;
if (newList != this.mList) {
我认为这是问题所在。但是如何度过呢?我的意思是,开发人员肯定考虑过提交不同的有序列表?
不会调用该函数,因为 ListAdapter
不会将其视为另一个列表,因为它具有所有 相同的项目 只是顺序发生了变化。
@Override
public void submitList(@Nullable final List<T> list) {
super.submitList(list != null ? new ArrayList<>(list) : null);
}
所以要解决这个问题,你需要先用null
调用这个函数,然后立即用改变顺序的列表调用。
submitList(null);
submitList(orderChangedList);
当您连续调用这些行时,它违背了 ListAdapter 自动计算和动画列表更改的目的:
submitList(null);
submitList(orderChangedList);
意思是,您只清除了(null
)ListAdapter 的currentList,然后提交了(.submitList()
)一个新的List。因此,在这种情况下不会看到相应的动画,只会刷新整个 RecyclerView。
解决方案是在您的 ListAdapter 中实现 .submitList( List<T> list)
方法,如下所示:
public void submitList(@Nullable List<T> list) {
mDiffer.submitList(list != null ? new ArrayList<>(list) : null);
}
通过这种方式,您允许 ListAdapter 保留其 currentList 并将其 "diffed" 与 newList 一起使用,从而计算动画,而不是 "diffing" 与 null
。
注意:但是,当然,如果新列表包含与原始列表相同顺序的相同项目,则不会发生更新动画。
而不是
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)
newList
和 mList
都指的是同一个列表实例,因此无论您对该列表进行了哪些更改,它都等于自身,并忽略您的更新。
在 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
属性,以避免此问题。
要添加 Carson 的答案,这是一种更好的方法,您可以在 Kotlin 中保持 submitList
的优点,如下所示:
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
})
只需调用 listAdapter.notifyDataSetChanged()
,ListAdapter
将根据提交的值重新绘制列表。
我遇到了类似的问题,但不正确的渲染是由 setHasFixedSize(true) 和 android:layout_height="wrap_content" 的组合引起的。第一次为适配器提供了一个空列表,因此高度从未更新并且为 0。无论如何,这解决了我的问题。其他人可能有同样的问题,并会认为是适配器的问题。
android recyclerview ListAdapter 示例,RecyclerView ListAdapter。 ListAdapter 是一个显示列表的 RecyclerView 适配器。这在 RecyclerView 27.1+ 中可用,如果您无法扩展适配器,则相同的功能也存在于 AsyncListDiffer class 中。 ListAdapter 可帮助您使用随时间更改内容的 RecyclerView。 usersList.observe(这个, 列表 -> adapter.submitList(列表)); recyclerView.setAdapter( 适配器); } } class UserAdapter extends ListAdapter
所有功劳都归功于此人:
https://www.xspdf.com/help/50031492.html
问题是提交的新列表没有呈现。
androidx.recyclerview:recyclerview:1.2.0-beta02
暂时的解决办法是在新列表提交后平滑滚动到任意位置,我做到顶部。
movieListAdapter.submitList(list) {
binding.recycler.smoothScrollToPosition(0)
}
如果您启用了 setHasFixedSize(true)
,请删除此行。
"RecyclerView 如果能提前知道 RecyclerView 的大小不受适配器内容的影响,就可以进行多项优化...."
我正在使用 RecyclerView
和 ListAdapter (which uses AsyncListDiffer 来计算和动画更改列表时的变化)。
问题是,如果我 submit()
一些列表,然后重新排序该列表,然后再次 submit()
,没有任何反应。
如何强制 ListAdapter
评估这个新列表,即使它是 "the same"(但顺序已更改)?
新发现:
我检查了 submitList() 的源代码,在开始时有一个检查:
public void submitList(@Nullable final List<T> newList) {
final int runGeneration = ++this.mMaxScheduledGeneration;
if (newList != this.mList) {
我认为这是问题所在。但是如何度过呢?我的意思是,开发人员肯定考虑过提交不同的有序列表?
不会调用该函数,因为 ListAdapter
不会将其视为另一个列表,因为它具有所有 相同的项目 只是顺序发生了变化。
@Override
public void submitList(@Nullable final List<T> list) {
super.submitList(list != null ? new ArrayList<>(list) : null);
}
所以要解决这个问题,你需要先用null
调用这个函数,然后立即用改变顺序的列表调用。
submitList(null);
submitList(orderChangedList);
当您连续调用这些行时,它违背了 ListAdapter 自动计算和动画列表更改的目的:
submitList(null);
submitList(orderChangedList);
意思是,您只清除了(null
)ListAdapter 的currentList,然后提交了(.submitList()
)一个新的List。因此,在这种情况下不会看到相应的动画,只会刷新整个 RecyclerView。
解决方案是在您的 ListAdapter 中实现 .submitList( List<T> list)
方法,如下所示:
public void submitList(@Nullable List<T> list) {
mDiffer.submitList(list != null ? new ArrayList<>(list) : null);
}
通过这种方式,您允许 ListAdapter 保留其 currentList 并将其 "diffed" 与 newList 一起使用,从而计算动画,而不是 "diffing" 与 null
。
注意:但是,当然,如果新列表包含与原始列表相同顺序的相同项目,则不会发生更新动画。
而不是
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)
newList
和 mList
都指的是同一个列表实例,因此无论您对该列表进行了哪些更改,它都等于自身,并忽略您的更新。
在 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
属性,以避免此问题。
要添加 Carson 的答案,这是一种更好的方法,您可以在 Kotlin 中保持 submitList
的优点,如下所示:
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
})
只需调用 listAdapter.notifyDataSetChanged()
,ListAdapter
将根据提交的值重新绘制列表。
我遇到了类似的问题,但不正确的渲染是由 setHasFixedSize(true) 和 android:layout_height="wrap_content" 的组合引起的。第一次为适配器提供了一个空列表,因此高度从未更新并且为 0。无论如何,这解决了我的问题。其他人可能有同样的问题,并会认为是适配器的问题。
android recyclerview ListAdapter 示例,RecyclerView ListAdapter。 ListAdapter 是一个显示列表的 RecyclerView 适配器。这在 RecyclerView 27.1+ 中可用,如果您无法扩展适配器,则相同的功能也存在于 AsyncListDiffer class 中。 ListAdapter 可帮助您使用随时间更改内容的 RecyclerView。 usersList.observe(这个, 列表 -> adapter.submitList(列表)); recyclerView.setAdapter( 适配器); } } class UserAdapter extends ListAdapter 所有功劳都归功于此人:
https://www.xspdf.com/help/50031492.html
问题是提交的新列表没有呈现。
androidx.recyclerview:recyclerview:1.2.0-beta02
暂时的解决办法是在新列表提交后平滑滚动到任意位置,我做到顶部。
movieListAdapter.submitList(list) {
binding.recycler.smoothScrollToPosition(0)
}
如果您启用了 setHasFixedSize(true)
,请删除此行。
"RecyclerView 如果能提前知道 RecyclerView 的大小不受适配器内容的影响,就可以进行多项优化...."