NotifyDataSetChanged- RecyclerView - 是异步调用吗?

NotifyDataSetChanged- RecyclerView -Is it an asynchronous call?

我正在尝试在回收站视图上执行 notifyDataSetChanged 后遵循一组语句。但是当我调试我的应用程序时,调试器在进入 recyclerview 适配器的 onBindViewHolder 之前到达我的 notifyDataSetChanged 之后的下几行。所以我的问题是- notifyDataSetChanged 是异步调用吗?如果是,我们会收到回调吗? PS:我已经用谷歌搜索了这个答案,但找不到合适的答案,这就是我向社区提问的原因。

TLDR:不可以。您只能从 UI 线程 中调用 notifyDatasetChanged() here 对 UI 进行的更改只能在 主线程 上完成。这使得调用同步。

此调用旨在使用更改后的 elements.It 重绘 ui 就像在视图上调用 requestFocus()

来自documentation

RecyclerView will attempt to synthesize visible structural change events for adapters that report that they have stable IDs when this method is used. This can help for the purposes of animation and visual object persistence but individual item views will still need to be rebound and relaid out.

因为视图是重绘因为数据集需要改变,它必须在主UI线程上(只有主循环器(即UI线程)可以修改视图)。

您可以有多个 AdapterObservers,它们可以在 ui 上执行您需要的操作。

也来自文档:

  • This event does not specify what about the data set has changed, forcing * any observers to assume that all existing items and structure may no longer be valid. * LayoutManagers will be forced to fully rebind and relayout all visible views.

默认的观察者将假定所有数据都已从 Recycler 视图的源代码中更改:

 public final void notifyDataSetChanged() {
        mObservable.notifyChanged();
    }

这是一个同步调用,应避免并用作 last resort

RecyclerView作者在这里,

当您调用 notifyDataSetChanged 时,RecyclerView 会使数据无效但不会更新 UI 直到下一个动画帧。这就是 android 视图系统的工作原理。当小部件无效时(例如更改其数据),它 请求布局 这意味着它将在下一次视图遍历中重新测量和重新布局。这样做是为了让我们可以批处理所有更改,直到下一次屏幕更新为止。这就是 notifyDataSetChange 不会立即触发 onBind 的原因。

所以是的,您可以将其称为 异步调用 但这并不意味着您可以 运行 它是多线程的(这是两个完全不同的概念).您仍然必须 在主线程上对您的适配器进行所有更改。当你改变适配器时,你必须立即通知 RecyclerView,这就是为什么通知也必须在主线程上。

此限制的原因是如果数据集在布局期间发生更改,布局管理器很难恢复到稳定状态(例如想象 RecyclerView 调用 onBind(5) 并且项目 5 是同时在另一个线程中删除)。此外,考虑到此类更改将需要大量同步,这将是一个很大的性能损失,没有任何好处。这就是为什么所有 UI 组件都是单线程的。

我遇到这个问题是因为我需要根据我的 recyclerview 的大小进行一些布局重新配置,并且由于我将高度设置为 wrap_content,只要它的数据发生变化,大小就会发生变化。为了有效地响应布局更改,您可以使用布局管理器的一个简短子类(在我的例子中是 LinearLayoutManager)并覆盖 onLayoutCompleted:

recyclerView.setLayoutManager(new LinearLayoutManager(getContext()){
        @Override
        public void onLayoutCompleted (RecyclerView.State state){
            super.onLayoutCompleted(state);
            // update UI for new layout
        }
    });

在我的例子中,我需要在 RecyclerView 上的尺寸发生变化后滚动我的 ScrollView,这段代码可以解决问题。