Android DiffUtil.ItemCallback areContentsTheSame具有不同的ID [英] Android DiffUtil.ItemCallback areContentsTheSame with different IDs

查看:644
本文介绍了Android DiffUtil.ItemCallback areContentsTheSame具有不同的ID的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用RecyclerView来显示从数据库中检索为Java对象的项目列表.对象中的字段之一是数据库中项目的ID,因此可以对其执行进一步的操作.我的areContentsTheSame实现比较对象中的各个字段,以确定项目的内容是否已更改.

I'm using a RecyclerView to display a list of items that are retrieved from a database as Java objects. One of the fields in the object is the ID of the item in the database, so that further operations can be performed with it. My areContentsTheSame implementation compares various fields in the objects to determine if the contents of the item has changed.

问题在于,有时刷新数据源时,项的ID会更改,而可见内容不会更改(即,从数据库中删除相同的项,然后再次添加它们,从而在此过程中更改其ID).在这种情况下,我当前的areContentsTheSame实现返回true.但是,当areContentsTheSame返回true时,不会重新绑定RecyclerView视图(对于areContentsTheSame返回true的项目,不会调用onBindViewHolder),因此这些视图仍保留对包含旧ID的旧对象,因此在尝试对该项目执行某些操作时会导致错误(例如,用户点击它以显示它).

The problem is that sometimes when the data source is refreshed the ID of the item changes without the visible contents changing (i.e. the same items are removed from the database and then added again, changing their ID in the process). In this case, my current areContentsTheSame implementation returns true. But when areContentsTheSame returns true, the RecyclerView views are not re-bound (onBindViewHolder is not called for the items for which areContentsTheSame returns true), so the views still hold a reference to the old object which contains the old ID thus causing an error when trying to do something with that item (such as the user tapping on it to display it).

我尝试使ID更改时areContentsTheSame返回false,即使未发生可见的更改也迫使视图重新绑定,但这会导致即使项目出现,项目更改"动画仍会显示并没有明显改变.我想要的是一种在不显示areContentsTheSame返回false的情况下强制重新绑定视图的方法,或者是areContentsTheSame返回true并触发重新绑定而不显示动画的方法.

I tried making areContentsTheSame return false when the ID changes, forcing the views to be re-bound even though no visible change has taken place, but this causes the "item changed" animation to show even though the item has not visibly changed. What I want is a way to either force the views to be re-bound without areContentsTheSame returning false or a way for areContentsTheSame to return true and trigger the re-binding without the animation being shown.

推荐答案

实现所需目标的最佳方法是覆盖

The best way to achieve what you want is to override the getChangePayload() method in your DiffUtil.Callback implementation.

areItemsTheSame(int, int)为两项返回true并且areContentsTheSame(int, int)为两项返回false时,DiffUtil调用此方法以获取有关更改的有效负载.

When areItemsTheSame(int, int) returns true for two items and areContentsTheSame(int, int) returns false for them, DiffUtil calls this method to get a payload about the change.

例如,如果将DiffUtilRecyclerView一起使用,则可以返回该项目中更改的特定字段,而ItemAnimator可以使用该信息来运行正确的动画.

For example, if you are using DiffUtil with RecyclerView, you can return the particular field that changed in the item and your ItemAnimator can use that information to run the correct animation.

默认实现返回null.

因此,请确保您的areContentsTheSame()方法在数据库ID更改时返回false,然后实现getChangePayload()来检查这种情况并返回非空值.也许是这样的:

So, make sure that your areContentsTheSame() method returns false when the database id changes, and then implement getChangePayload() to check for this case and return a non-null value. Maybe something like this:

@Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
    if (onlyDatabaseIdChanged(oldItemPosition, newItemPosition)) {
        return Boolean.FALSE;
    } else {
        return null;
    }
}

从该方法返回什么对象都没有关系,只要在不想看到默认的更改动画的情况下它不为null.

It doesn't matter what object you return from this method, as long as it's not null in the case where you don't want to see the default change animation be played.

有关为什么可行的更多详细信息,请参见以下问题的答案: https://stackoverflow .com/a/47355363/8298909

For more details on why this works, see the answer to this question: https://stackoverflow.com/a/47355363/8298909

这篇关于Android DiffUtil.ItemCallback areContentsTheSame具有不同的ID的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆