Android DiffUtil.ItemCallback isContentsTheSame具有不同的ID

时间:2018-05-22 19:13:07

标签: android database android-recyclerview pojo

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

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

我尝试在ID更改时使false返回areContentsTheSame,即使没有发生可见的更改,也会强制重新绑定视图,但这会导致“项目已更改”动画显示即使该项目没有明显改变。我想要的是一种强制视图重新绑定而不false返回areContentsTheSametrue返回<asp:Image ID="Image1" runat="server" ImageUrl="~/images/" /> 并触发重新绑定的方法没有显示动画。

2 个答案:

答案 0 :(得分:4)

实现目标的最佳方法是覆盖DiffUtil.Callback实施中的getChangePayload()方法。

  

areItemsTheSame(int, int)为两个项目返回trueareContentsTheSame(int, int)为其返回false时,DiffUtil会调用此方法获取有关更改的有效负载。< / p>      

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

     

默认实现返回null

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

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

从此方法返回的对象并不重要,只要在您不想看到默认更改动画的情况下它不为空。

有关为什么的详细信息,请参阅此问题的答案:https://stackoverflow.com/a/47355363/8298909

答案 1 :(得分:0)

大多数答案找出了DiffUtil的一些基本示例,其中 代码看起来像

class MyDiffUtil(  private val oldList: List<Item>, private val newList: 
    List<Item> ) : DiffUtil.Callback() {

    override fun getOldListSize(): Int = oldList.size

    override fun getNewListSize(): Int = newList.size

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition].id == newList[newItemPosition].id
    }

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition].id == newList[newItemPosition].id
    }

}
当新项目添加或删除具有列表ID的项目时,上述代码中的

将正常工作。但是当id保持不变但更改了一些其他内容时,适配器就不会更新,因为这种和平的代码

    return oldList[oldItemPosition].id == newList[newItemPosition].id

在这里,我们检查了id而不是其他项目,因此您只需删除id并编写此新代码

class MyDiffUtil(  private val oldList: List<Item>, private val newList: 
    List<Item> ) : DiffUtil.Callback() {

    override fun getOldListSize(): Int = oldList.size

    override fun getNewListSize(): Int = newList.size

    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition] == newList[newItemPosition]
    }

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldList[oldItemPosition] == newList[newItemPosition]
    }
}