我正在使用RecyclerView
显示从数据库中检索为Java对象的项目列表。对象中的字段之一是数据库中项目的ID,因此可以对其执行进一步的操作。我的areContentsTheSame
实现比较对象中的各个字段,以确定项目的内容是否已更改。
问题在于,有时在刷新数据源时,项的ID会更改而可见内容不会更改(即,从数据库中删除相同的项,然后再次添加它们,从而在此过程中更改其ID)。在这种情况下,我当前的areContentsTheSame
实现返回true
。但是,当areContentsTheSame
返回true
时,不会重新绑定(bind)RecyclerView
View (对于onBindViewHolder
返回areContentsTheSame
的项目,不会调用true
),因此 View 仍然持有对包含旧ID的旧对象的引用,从而在以下情况下导致错误:尝试对该项目执行某项操作(例如用户点击它以显示它)。
我尝试在ID更改时使areContentsTheSame
返回false
,即使没有发生可见的更改也迫使 View 重新绑定(bind),但这会导致显示“项目更改”动画,即使该项目没有明显更改也是如此。我想要的是一种在不让areContentsTheSame
返回false
的情况下强制重新绑定(bind) View 的方法,或者是让areContentsTheSame
返回true
并触发重新绑定(bind)而不显示动画的方法。
最佳答案
实现所需目标的最佳方法是在getChangePayload()
实现中重写 DiffUtil.Callback
方法。
因此,请确保当数据库ID更改时,您的areContentsTheSame()
方法返回false
,然后实现getChangePayload()
来检查这种情况并返回非null值。也许是这样的:
@Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
if (onlyDatabaseIdChanged(oldItemPosition, newItemPosition)) {
return Boolean.FALSE;
} else {
return null;
}
}
从此方法返回什么对象都没有关系,只要在您不希望播放默认的更改动画的情况下它不为null。有关为何有效的更多详细信息,请参见以下问题的答案:https://stackoverflow.com/a/47355363/8298909
关于Android DiffUtil.ItemCallback areContentsTheSame具有不同的ID,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50474945/