AsyncListDiffer onAfterSubmitList 监听器
AsyncListDiffer onAfterSubmitList Listener
我试图仅在 mDiffer.submitlist(list)
完成 "diffing" 并为列表设置动画 updates/changes 后调用 recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,null,0)
。
我可以使用 onAfterSubmitList(Callback callback)
的 AsyncListDiffer 功能来实现这一点吗?
如果没有,是否可以找出 submitList()
何时完成任务,以便我可以将我的 scrollToPosition(0)
放在那里?
您可以通过聆听(或您的需要)从 registerAdapterDataObserver
方法中获益,即:
listAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
//
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
}
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
}
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
}
})
您可以在需要时使用unregisterAdapterDataObserver
清除adapterObserver
的寄存器。
2020 年 7 月更新:
Google为此添加了回调!参见:https://developer.android.com/reference/androidx/recyclerview/widget/AsyncListDiffer#submitList(java.util.List%3CT%3E,%20java.lang.Runnable)
上一个回答,来自过去的糟糕时光:
首先,我不敢相信 Google 没有为此提供回调。
我深入研究了 AsyncListDiffer
的源代码,我发现当所有的 RecyclerView 更新都完成后,可以接收到回调 - 但是接收这个回调的方式很奇怪。
您需要创建 BatchingListUpdateCallback
的子 class,然后将 ListUpdateCallback
(或大多数情况下的 AdapterListUpdateCallback
)包裹在其中。
然后,您应该覆盖 dispatchLastEvent
。 AsyncListDiffer
将在所有但其中一个更新已发送后调用它。在您的 dispatchLastEvent
中,您需要调用超级实现,这样您就不会破坏任何东西。您还需要调用自定义回调,这是您的方式。
在 Kotlin 中看起来像:
class OnDiffDoneListUpdateCallback(
listUpdateCallback: ListUpdateCallback,
private val onDiffDoneCallback: () -> Unit
) : BatchingListUpdateCallback(listUpdateCallback) {
override fun dispatchLastEvent() {
super.dispatchLastEvent()
onDiffDoneCallback()
}
}
最后一步是将您的自定义 OnDiffDoneListUpdateCallback
提供给 AsyncListDiffer
。为此,您需要自己初始化 AsyncListDiffer
- 如果您使用 ListAdapter
或类似的东西,您需要重构以便控制 AsyncListDiffer
.
在 Kotlin 中,它看起来像:
private val asyncListDiffer = AsyncListDiffer<ItemType>(
OnDiffDoneListUpdateCallback(AdapterListUpdateCallback(adapter)) {
// here's your callback
doTheStuffAfterDiffIsDone()
},
AsyncDifferConfig.Builder<ItemType>(diffCallback).build()
)
编辑:
当然,我忘记了边缘情况!
有时,dispatchLastEvent
不会被调用,因为 AsyncListDiffer
认为更新微不足道。这是它所做的检查:
if (newList == mList) {
...
return;
}
// fast simple remove all
if (newList == null) {
...
mUpdateCallback.onRemoved(0, countRemoved);
return;
}
// fast simple first insert
if (mList == null) {
...
mUpdateCallback.onInserted(0, newList.size());
return;
}
我建议您自己进行这些检查,就在您致电 asyncListDiffer.submitList(list)
之前。但当然,这不可能那么容易! mList
是私有的,如果 mList
为空,getCurrentList
将 return 一个空列表,因此对于此检查无用。相反,您必须使用反射来访问它:
val listField = AsyncListDiffer::class.java.getDeclaredField("mList")
listField.isAccessible = true
val asyncDifferList = listField.get(asyncListDiffer) as List<ItemType>?
asyncListDiffer.submitList(newList)
if(asyncDifferList == null) {
onDiffDone()
}
if(newList == null) {
onDiffDone()
}
if(newList == asyncDifferList) {
onDiffDone()
}
编辑 2:现在,我知道你在说什么 - 肯定有更简单、更简单的方法来做到这一点?答案是……是的!只需将整个 AsyncListDiffer
class 复制到您的项目中,然后自己添加回调即可!
我试图仅在 mDiffer.submitlist(list)
完成 "diffing" 并为列表设置动画 updates/changes 后调用 recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,null,0)
。
我可以使用 onAfterSubmitList(Callback callback)
的 AsyncListDiffer 功能来实现这一点吗?
如果没有,是否可以找出 submitList()
何时完成任务,以便我可以将我的 scrollToPosition(0)
放在那里?
您可以通过聆听(或您的需要)从 registerAdapterDataObserver
方法中获益,即:
listAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
//
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
}
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
}
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
}
})
您可以在需要时使用unregisterAdapterDataObserver
清除adapterObserver
的寄存器。
2020 年 7 月更新:
Google为此添加了回调!参见:https://developer.android.com/reference/androidx/recyclerview/widget/AsyncListDiffer#submitList(java.util.List%3CT%3E,%20java.lang.Runnable)
上一个回答,来自过去的糟糕时光:
首先,我不敢相信 Google 没有为此提供回调。
我深入研究了 AsyncListDiffer
的源代码,我发现当所有的 RecyclerView 更新都完成后,可以接收到回调 - 但是接收这个回调的方式很奇怪。
您需要创建 BatchingListUpdateCallback
的子 class,然后将 ListUpdateCallback
(或大多数情况下的 AdapterListUpdateCallback
)包裹在其中。
然后,您应该覆盖 dispatchLastEvent
。 AsyncListDiffer
将在所有但其中一个更新已发送后调用它。在您的 dispatchLastEvent
中,您需要调用超级实现,这样您就不会破坏任何东西。您还需要调用自定义回调,这是您的方式。
在 Kotlin 中看起来像:
class OnDiffDoneListUpdateCallback(
listUpdateCallback: ListUpdateCallback,
private val onDiffDoneCallback: () -> Unit
) : BatchingListUpdateCallback(listUpdateCallback) {
override fun dispatchLastEvent() {
super.dispatchLastEvent()
onDiffDoneCallback()
}
}
最后一步是将您的自定义 OnDiffDoneListUpdateCallback
提供给 AsyncListDiffer
。为此,您需要自己初始化 AsyncListDiffer
- 如果您使用 ListAdapter
或类似的东西,您需要重构以便控制 AsyncListDiffer
.
在 Kotlin 中,它看起来像:
private val asyncListDiffer = AsyncListDiffer<ItemType>(
OnDiffDoneListUpdateCallback(AdapterListUpdateCallback(adapter)) {
// here's your callback
doTheStuffAfterDiffIsDone()
},
AsyncDifferConfig.Builder<ItemType>(diffCallback).build()
)
编辑: 当然,我忘记了边缘情况!
有时,dispatchLastEvent
不会被调用,因为 AsyncListDiffer
认为更新微不足道。这是它所做的检查:
if (newList == mList) {
...
return;
}
// fast simple remove all
if (newList == null) {
...
mUpdateCallback.onRemoved(0, countRemoved);
return;
}
// fast simple first insert
if (mList == null) {
...
mUpdateCallback.onInserted(0, newList.size());
return;
}
我建议您自己进行这些检查,就在您致电 asyncListDiffer.submitList(list)
之前。但当然,这不可能那么容易! mList
是私有的,如果 mList
为空,getCurrentList
将 return 一个空列表,因此对于此检查无用。相反,您必须使用反射来访问它:
val listField = AsyncListDiffer::class.java.getDeclaredField("mList")
listField.isAccessible = true
val asyncDifferList = listField.get(asyncListDiffer) as List<ItemType>?
asyncListDiffer.submitList(newList)
if(asyncDifferList == null) {
onDiffDone()
}
if(newList == null) {
onDiffDone()
}
if(newList == asyncDifferList) {
onDiffDone()
}
编辑 2:现在,我知道你在说什么 - 肯定有更简单、更简单的方法来做到这一点?答案是……是的!只需将整个 AsyncListDiffer
class 复制到您的项目中,然后自己添加回调即可!