DiffUtil ItemCallback areContentsTheSame() 在更新 ListAdapter 上的项目后始终返回 true

fmi*_*les 10 android listadapter android-recyclerview android-diffutils

在使用 ListAdapter 时,我注意到在更新项目后DiffUtil.ItemCallback areContentsTheSame()方法总是返回 true。调试代码我意识到旧的和新的项目完全一样(旧状态消失了)。因此,没有调用ListAdapter onBindViewHolder()方法来更新列表中的相应行(只有项目的顺序通过漂亮的动画更改)。

检查 Stackoverflow 上的其他问题似乎是许多开发人员面临的常见问题:

ListAdapter 不更新 reyclerview 中的项目

编辑内容时 ListAdapter 未更新

DiffUtil.Callback 未按预期工作

Recyclerview + Listadapter 中的项目不会在更新时重绘

带有 DiffUtil.ItemCallback 的 ListAdapter 始终认为对象相同

当向 RecyclerView ListAdapter 提交新列表时,差异检查始终为 areContentsTheSame() 返回 true

但是,上述答案(如果有)都没有提供正确的解决方案。

它对我有用的唯一方法是每次观察者发出新结果时在 ListAdapter 上调用notifyDataSetChanged()

但是,如果通过强制 RecyclerView 重绘其内容(迄今为止显示的所有项目)而放弃了您可以获得的所有出色性能,那么使用 ListAdapter 和 submitList() 来通知更改的全部意义何在?

  1. notifyDataSetChanged()

即使它有效,如果您决定首先使用 ListAdapter,肯定不是正确的方法。

  1. viewModel.getObjects().observe(this, listOfObjects -> listAdapter.submitList(new ArrayList<>(listOfObjects)));

没用。

更新列表中的项目后,我希望看到相应行的 UI(不仅是排序顺序)上发生的相应更改。

Sha*_*dow 6

我不知道这是否是针对这种特定情况的解决方案,但从描述来看,这听起来与我最近经历的完全一样。

我第一次使用新的 Room + LiveData + ViewModel + DiffUtils 集成,在更新列表后更新 RecyclerView 中的项目时遇到了同样的问题。

我遇到的问题是由于我理解更新列表并允许 DiffUtils 完成它应该做的工作。希望以下内容足够清楚:

我在做什么:

  1. 用户使用对话框更新其项目
  2. RecyclerView 中的列表项更新为新信息
  3. Room 触发 LiveData 观察者,因为某些内容可能已更改
  4. RecyclerView DiffUtils 尝试检查旧适配器列表和新适配器列表之间的任何差异
  5. 未检测到任何新内容
  6. 不触发适配器更新其 UI

我的错误是认为问题出在 .5 中,这导致我花了半天时间来回调试问题。最终,我偶然发现了一个 SO 问题(目前无法找到),这使我找到了问题的正确来源。该问题确实位于 .2 - 更新列表中的项目。

这是问题所在,因为我们甚至在 DiffUtils 有机会比较新旧列表更改之前就使用新更改更新了我们的 CURRENT 适配器列表。这意味着每次 DiffUtils 总是将列表与已经包含新列表更改的旧列表进行比较。

解决方案?不要更新列表项,因为它是一个对象,并且列表对象保持相同的引用,导致在使用/引用它的任何地方都更新相同的实例。而是克隆项目对象(如在深度克隆中,我知道这可能很烦人),应用用户对克隆对象所做的更改,然后使用该克隆更新房间数据库中的项目条目。不要用克隆替换适配器列表项,保留原始项,我们只想更新数据库中的信息,而不是列表,因为 DiffUtils 会处理这些。

我们在这里所做的基本上是为我们的 Room 数据库创建一个更新有效负载,然后触发 LiveData 观察器将旧列表与新列表(包含更新的项目数据)进行比较,从而在两个列表之间进行预期的更改检测。


简而言之;

做这个:

  • 深度克隆适配器列表项
  • 仅使用新信息更新克隆
  • 使用克隆信息更新数据库

不要这样做:

  • 直接更新适配器列表项
  • 使用列表项信息更新数据库


leo*_*ura 0

我花了很多时间才发现我遇到了与这篇文章中描述的相同的问题。我尝试了很多解决方案,但最终我意识到我在不知不觉中搞砸了。如果您遇到同样的问题,请检查您是否没有先更新 UI 并调用写入命令来更新存储库上的值。就我而言,我正在更新 LiveData 对象,然后更新 Firebase 数据库上的该值。引起该问题的原因是我的 UI 正在侦听该 LiveData 对象上的更改,因此我的 Firebase 数据库观察者检测到更改,调用了 ListAdapter,但看起来没有任何更改。

为了解决这个问题,我删除了更新 LiveData 对象的行,并且只调用 Firebase 数据库发送更改。