我正在将RecyclerView
与ListAdapter一起使用(当替换列表时,它使用AsyncListDiffer来计算和动画化更改)。
问题在于,如果我submit()
一些列表,然后重新排序该列表,然后再次submit()
,则什么也没有发生。
即使列表“相同”,我如何强制ListAdapter
评估这个新列表(但顺序已更改)?
新发现:
我检查了submitList()的源代码,并且在开始时有一个检查:
public void submitList(@Nullable final List<T> newList) {
final int runGeneration = ++this.mMaxScheduledGeneration;
if (newList != this.mList) {
我认为这是问题所在。但是如何克服呢?我的意思是,开发人员肯定会考虑提交其他有序列表吗?
答案 0 :(得分:4)
代替
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.toList() // Unintuitive way to copy a list
newList.first().isFavourite = false // Do whatever modifications you want
submitList(newList)
答案 1 :(得分:2)
该函数将不会被调用,因为ListAdapter
不会将其视为另一个列表,因为它具有所有相同项目,只是顺序被更改了。
@Override
public void submitList(@Nullable final List<T> list) {
super.submitList(list != null ? new ArrayList<>(list) : null);
}
因此,要解决此问题,您需要先使用null
调用此函数,然后立即使用顺序已更改的列表进行调用。
submitList(null);
submitList(orderChangedList);
答案 2 :(得分:1)
当您连续调用以下行时,它违反了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,并使其与newList“差异化”,从而使计算出的动画不同于与null
“差异化”。
注意:但是,如果newList包含与原始List顺序相同的项目,则不会发生更新动画。
答案 3 :(得分:1)
如果您启用了 setHasFixedSize(true)
,请删除此行。
“如果 RecyclerView 能够提前知道 RecyclerView 的大小不受适配器内容的影响,它可以进行多次优化......”
答案 4 :(得分:0)
要添加到卡森的答案(这是一种更好的方法),您可以按照以下说明在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
})
答案 5 :(得分:0)
只需调用listAdapter.notifyDataSetChanged()
,ListAdapter
就会根据提交的值重新绘制列表。
答案 6 :(得分:0)
我遇到了类似的问题,但不正确的渲染是由 setHasFixedSize(true) 和 android:layout_height="wrap_content" 的组合引起的。第一次为适配器提供了一个空列表,因此高度从未更新并且为 0。无论如何,这解决了我的问题。其他人可能有同样的问题,并会认为这是适配器的问题。
android recyclerview listadapter 示例,RecyclerView ListAdapter。 ListAdapter 是一个显示列表的 RecyclerView 适配器。这在 RecyclerView 27.1+ 中可用,如果您无法扩展适配器,则 AsyncListDiffer 类中也存在相同的功能。 ListAdapter 可帮助您使用随时间更改内容的 RecyclerViews。 usersList.observe(this, list -> adapter.submitList(list)); recyclerView.setAdapter( adapter);类 UserAdapter 扩展 ListAdapter
答案 7 :(得分:0)
问题是提交的新列表没有呈现。
androidx.recyclerview:recyclerview:1.2.0-beta02
临时解决方案是在新列表提交后平滑滚动到任何位置,我做到顶部。
movieListAdapter.submitList(list) {
binding.recycler.smoothScrollToPosition(0)
}