RecyclerView和DiffUtil - 并发梦魇

时间:2016-10-27 17:54:53

标签: android concurrency android-recyclerview diff android-support-library

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

  1. 将数据添加到list并通知适配器
  2. 需要将list替换为newList,这会有一些添加和一些删除的差异
  3. 在后台调用DiffUtil.calculateDiff并获取DiffResultlist的{​​{1}},并向将使用newList的主线程发送消息致电newList
  4. 在处理该消息之前,用户对导致DiffResult.dispatchUpdatesTo突变的主线程采取行动
  5. 处理消息,list被设置为新数据源并且newList运行导致基础数据的视图不一致+自DiffResult.dispatchUpdatesTo以来任何突变丢失计算
  6. 那不好,所以让我们从第3步开始改变:

    1. DiffResults设置为新数据源,在后台调用newList并获取DiffUtil.calculateDiffDiffResult的{​​{1}},然后发送消息给将调用list
    2. 的主要线程
    3. 在处理该消息之前,用户对导致newList突变的主线程采取操作,并通知适配器,导致数据视图不一致,因为尚未调用DiffResult.dispatchUpdatesTo
    4. 这方面有更多变化,但没有一个是好的。似乎将newList与大型数据集和变更集可靠地使用的唯一方法是在调用DiffResult.dispatchUpdatesTo之前禁用或排队所有更新。

      我错过了会导致上述错误的事情吗?

2 个答案:

答案 0 :(得分: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;
        }

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

答案 1 :(得分:2)

我最终堆叠更新以在DiffUtil计算期间管理用户交互,并且仍然只在主线程中访问数据集。

我在那里写了:https://geoffreymetais.github.io/code/diffutil-threading/