AsyncListDiffer onAfterSubmitList 监听器

aLL*_*aLL 6 android android-asynclistdiffer

我尝试recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,null,0)仅在mDiffer.submitlist(list)完成“比较”并对列表更新/更改进行动画处理后才进行调用。

是否有 AsyncListDiffer 功能onAfterSubmitList(Callback callback)可以用来实现此目的?

如果没有,是否有办法找出何时submitList()完成其任务,以便我可以将其scrollToPosition(0)放在那里?

Luk*_*uke 7

2020 年 7 月更新:

谷歌为此添加了回调!请参阅: https: //developer.android.com/reference/androidx/recyclerview/widget/AsyncListDiffer#submitList(java.util.List%3CT%3E,%20java.lang.Runnable)

以前的答案,来自糟糕的过去:

首先,我不敢相信谷歌没有为此提供回调。

我深入研究了 的源代码AsyncListDiffer,发现当所有 RecyclerView 更新完成后,有可能收到回调 - 但接收此回调的方式很奇怪。

您需要创建 的子类BatchingListUpdateCallback,然后将您的ListUpdateCallback(或AdapterListUpdateCallback在大多数情况下)包装在其中。

然后,您应该重写dispatchLastEvent. AsyncListDiffer在除其中一项更新之外的所有更新均已发送后,将调用此方法。在您的 中dispatchLastEvent,您需要调用超级实现,这样就不会破坏任何东西。您还需要调用自定义回调,这是您的方法。

在 Kotlin 中看起来像:

class OnDiffDoneListUpdateCallback(
    listUpdateCallback: ListUpdateCallback,
    private val onDiffDoneCallback: () -> Unit
) : BatchingListUpdateCallback(listUpdateCallback) {
    override fun dispatchLastEvent() {
        super.dispatchLastEvent()
        onDiffDoneCallback()
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一步是将您的自定义提供OnDiffDoneListUpdateCallbackAsyncListDiffer. 为此,您需要AsyncListDiffer自己初始化 - 如果您正在使用ListAdapter或类似的东西,您需要重构以便您可以控制AsyncListDiffer.

在 Kotlin 中,这看起来像:

private val asyncListDiffer = AsyncListDiffer<ItemType>(
        OnDiffDoneListUpdateCallback(AdapterListUpdateCallback(adapter)) {
            // here's your callback
            doTheStuffAfterDiffIsDone()
        },
        AsyncDifferConfig.Builder<ItemType>(diffCallback).build()
    )
Run Code Online (Sandbox Code Playgroud)

编辑:当然,我忘记了边缘情况!

有时,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;
    }
Run Code Online (Sandbox Code Playgroud)

我建议您在致电之前亲自进行这些检查asyncListDiffer.submitList(list)。但当然,事情不可能那么容易!mList是私有的,getCurrentList如果为 null,将返回一个空列表mList,因此对于此检查毫无用处。相反,您必须使用反射来访问它:

    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()
    }
Run Code Online (Sandbox Code Playgroud)

编辑2:现在,我知道你在说什么——肯定有一种更简单、更简单的方法来做到这一点吗?答案是……是的!只需将整个AsyncListDiffer类复制到您的项目中,然后自己添加回调即可!