什么更好?循环中的 notifyDataSetChanged 或 notifyItemChanged?

What's better? notifyDataSetChanged or notifyItemChanged in loop?

所以我有一个 activity 和 RecyclerView,我想通过按下具有 onClickListener() 的按钮来更改 RecyclerView 中每个项目的 TextView在 activity。

我想知道什么在性能方面更好:

  1. 使用 notifyDataSetChanged 个。
  2. 使用条件循环,例如 int i 小于 List.size(),其中 notifyItemChanged 会被调用几次。

在这两种情况下,我都在 RecyclerView 适配器中创建布尔变量,onBindViewHolder 使用它来了解如何更新项目。默认情况下它是假的,点击按钮后它变为真所以 onBindViewHolder 以不同的方式更新项目。

我也想知道这种方法是否合适。

如果所有数据项都不再有效,我肯定会打电话给 notifyDataSetChanged()。当你调用notifyItemChanged(mPos)的时候,就相当于调用了notifyItemRangeChanged(mPos, 1),而且每次调用的时候,也会调用requestLayout()。另一方面,当您调用 notifyDataSetChanged()notifyItemRangeChanged(0, mList.size()) 时,只有一次调用 requestLayout().

您现在的问题应该是,调用 notifyDataSetChanged()notifyItemRangeChanged(0, mList.size()) 哪个更好?对于那个我没有答案。

如果您只是更新视图的一部分,请使用 notifyItemRangeChanged()notifyItemChanged() 而不是 notifiyDataSetChanged()。这里的区别与 结构变化 项目变化 有关。这是在 android 开发人员 RecyclerView.Adapter 文档中找到的 here

这是关于两种变化之间差异的另一个花絮:

There are two different classes of data change events, item changes and structural changes. Item changes are when a single item has its data updated but no positional changes have occurred. Structural changes are when items are inserted, removed or moved within the data set.

这取自上述页面,

If you are writing an adapter it will always be more efficient to use the more specific change events if you can. Rely on notifyDataSetChanged() as a last resort.

所以只是为了澄清使用notifyDataSetChanged()作为最后的手段,而是问问自己是否可以执行这些方法之一,以及是否可以使用它相反:

notifyItemChanged(int)
notifyItemInserted(int)
notifyItemRemoved(int)
notifyItemRangeChanged(int, int)
notifyItemRangeInserted(int, int)
notifyItemRangeRemoved(int, int)

这是有道理的,因为 notifyDataSetChanged() 几乎会尝试根据数据重新绘制所有内容,并且不会对其进行任何先前的假设,而其他方法只会寻找变化。这意味着适配器必须做更多不必要的工作。这就是 notifyDataSetChanged() 所做的:

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.

这对于使用增量或范围方法也很有意义,因为您正在更改文本,您需要获取每个新文本,当您这样做时,您应该告诉适配器您更改了它。现在,如果您单击按钮并获取所有新文本值,并创建一个新列表或其他内容,然后调用 heavy notifyDataSetChanged().

我注意到 notifyItemChanged(mPos) 会触发 onBindVieHolder 对应的位置,即使它目前不可见。

对我来说,在所有元素的循环中调用它比 notifyDatasetChanged 只重绘可见元素的成本更高。

所以要小心处理大型数据集。