RecyclerView和DiffUtil - 并发梦魇

Eli*_*zer 8 concurrency diff android android-support-library android-recyclerview

DiffUtil建议的文档建议DiffUtil.DiffResult在后台线程上生成因为潜在的长计算时间.这对我来说似乎是一个坏主意,因为该线程可能在以下情况下对过时数据进行操作(假设list访问是线程安全的):

  1. 添加数据list并通知适配器
  2. 需要更换listnewList这将对一些添加和移除一些的差异
  3. DiffUtil.calculateDiff在后台调用并获取DiffResultfor listnewList,并将消息发送到将使用newList和调用的主线程DiffResult.dispatchUpdatesTo
  4. 在处理该消息之前,用户对导致突变的主线程采取操作 list
  5. 消息被处理,newList被设置为新的数据源并且DiffResult.dispatchUpdatesTo被运行导致基础数据的不一致视图+自DiffResults计算以来丢失任何突变

嗯,这不好,所以让我们从第3步开始改变:

  1. 设置newList为新的数据源,DiffUtil.calculateDiff在后台调用并获取DiffResultfor listnewList,并将消息发送到将调用的主线程DiffResult.dispatchUpdatesTo
  2. 在处理该消息之前,用户对导致突变的主线程采取操作newList,并通知适配器,导致数据视图不一致,因为DiffResult.dispatchUpdatesTo尚未调用

对此有更多的变化,但没有一个是好的.似乎可靠地使用DiffUtil大型数据集和变更集的唯一方法DiffResult.dispatchUpdatesTo是在调用之前禁用或排队所有更新.

我错过了会导致上述错误的内容吗?

Sir*_*lon 2

看一下 BatchingListUpdateCallback。它是包装主回调的类,当列表发生多次更改时,batchingListCallback 将仅通知一次主回调。

https://developer.android.com/reference/android/support/v7/util/BatchingListUpdateCallback.html

编辑

很抱歉我的答案不正确。

我查看了 DiffUtil 的源代码。我发现,无论如何,BatchingListUpdateCallback 都在dispatchUpdatesTo方法中使用。

 public void dispatchUpdatesTo(ListUpdateCallback updateCallback) {
        final BatchingListUpdateCallback batchingCallback;
        if (updateCallback instanceof BatchingListUpdateCallback) {
            batchingCallback = (BatchingListUpdateCallback) updateCallback;
        } else {
            batchingCallback = new BatchingListUpdateCallback(updateCallback);
            // replace updateCallback with a batching callback and override references to
            // updateCallback so that we don't call it directly by mistake
            //noinspection UnusedAssignment
            updateCallback = batchingCallback;
        }
Run Code Online (Sandbox Code Playgroud)

但作为正确方式的载体,这可能很有用:)