【问题标题】:What's better? notifyDataSetChanged or notifyItemChanged in loop?什么更好?循环中的 notifyDataSetChanged 或 notifyItemChanged?
【发布时间】:2016-02-20 17:41:07
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • notifyDataSetChanged 将重绘可见视图。如果我正确理解您的要求,我会选择那个。
  • 您是否查看过 RecyclerView 代码并查看 notifyDataSetChanged 中发生了什么?仅基于名称(而不是专业知识)听起来就像您想要的那样,因为您要立即重新验证整个数据集,而不是在单个项目上调用它,除非您要更改特定项目,否则这似乎很乏味。
  • @McAdam331 我的 RecyclerView 的项目是 CardView,里面有 TextView。我想一次更改所有可见卡片中的 TextView。

标签: android android-recyclerview android-viewholder


【解决方案1】:

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

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

有两类不同的数据变化事件,项目变化 和结构变化。项目更改是指单个项目有其 数据已更新,但没有发生位置变化。结构 更改是在数据中插入、删除或移动项目时 设置。

这是取自上述页面,

如果你正在编写一个适配器,它总是会更有效地使用 如果可以,更具体的更改事件。依靠 notifyDataSetChanged() 作为最后的手段。

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

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

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

这个事件没有说明数据集发生了什么变化, 迫使任何观察者假设所有现有的项目和结构 可能不再有效。 LayoutManagers 将被强制完全重新绑定 并重新布局所有可见视图。

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

【讨论】:

  • 我前几天的经历是,调用notifyItenChanged(x)不仅对x调用onBindViewHolder,对于其他viewholder的hash变化的item,我还是不知道是不是这样不过,这是一个 Android 错误,或者这是一种常见行为。
【解决方案2】:

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

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

【讨论】:

  • 我的适配器具有稳定的 ID,并且使用 notifyItemRangeChanged(0, list.size()) 被证明非常慢(对于 100 个项目的数据集长达 3 秒),而 notifyDataSetChanged() 几乎是即时的。对于前者,适配器出于某种原因重新创建了许多视图持有者,而对于后者,它们都被回收了。
【解决方案3】:

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

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

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

【讨论】:

    猜你喜欢
    • 2018-01-18
    • 1970-01-01
    • 1970-01-01
    • 2020-01-03
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多