(android) 我可以在我的 DiffUtill 实现中使用此代码吗?

(android) Can I use this code in my DiffUtill implementation?

我现在正在制作 DiffUtil class 以仅更新 RecyclerView 中更改的项目。

我看过其他几个示例代码。

比较两个对象时,比较的是areItemsTheSame()中class中定义的id等唯一值。

不过我觉得给List分配一个id或者unique value比较难,或者代码比较乱。

我必须这样定义和比较id吗?

我真的需要在 Model class 中定义一个唯一的 Id 变量来分隔每个对象吗? 或者我不应该只使用 equals()?

用这个是不是不仅要比较对象的地址,还要比较对象的内容?

作为附加问题

DiffUtil.CallBackDiffUtil.ItemCallBack有什么区别?

这是我的代码。

RoutineModel.java

public class RoutineModel {
    private ArrayList<RoutineDetailModel> routineDetailModels;
    private String routine;

    public RoutineModel(ArrayList<RoutineDetailModel> items, String routine) {
        this.routine = routine;
        this.routineDetailModels = items;
    }

    public ArrayList<RoutineDetailModel> getDetailItemList() {
        return routineDetailModels;
    }

    public int getDetailItemSize() {
        return routineDetailModels.size();
    }

    public String getRoutine() {
        return routine;
    }

    public void setRoutine(String routine) {
        this.routine = routine;
    }
}

RoutineDiffUtil.java

public class RoutineDiffUtil extends DiffUtil.Callback {
    private final List<RoutineModel> oldRoutineList;
    private final List<RoutineModel> newRoutineList;

    public RoutineDiffUtil(ArrayList<RoutineModel> oldRoutineList, ArrayList<RoutineModel> newRoutineList) {
        this.oldRoutineList = oldRoutineList;
        this.newRoutineList = newRoutineList;
    }

    @Override
    public int getOldListSize() {
        return oldRoutineList.size();
    }

    @Override
    public int getNewListSize() {
        return newRoutineList.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldRoutineList.equals(newRoutineList);
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return oldRoutineList.equals(newRoutineList);
    }
}

你误解了 areItemsTheSame()areContentsTheSame() 回调的含义。如您所见,其中有 oldItemPositionnewItemPosition 参数。您应该使用它们来比较特定项目——而不是列表本身。

areItemsTheSame()中你必须检查旧列表中“旧”位置的模型是否等于中“新”位置的模型新列表。这就是 DiffUtil 知道是否必须制作重新排序动画的方式。

areContentsTheSame() 当且仅当您在上一个回调中为它们 return true 时,才会为两个项目调用。在这里您必须检查“旧”和“新”模型的视觉表示是否相同。这就是 DiffUtil 知道它是否必须制作“项目更改”动画的方式。

要比较两个模型,您必须覆盖 equals()hashCode()。您可以在其中指定将两个模型视为相同的条件。例如,如果他们有相同的 routine。我不知道你任务的背景,所以我不能告诉你具体如何实现它们,但通常你只是比较所有领域。可能添加一个 id 字段也是一个好主意。然后,如果模型具有相同的 id,则您可以认为模型“相等”。在 hashCode() 中你可以 return Objects.hash(id).

现在,谈谈你关于 ItemCallback 的问题。正式地,这是来自文档的解释:

DiffUtil.Callback serves two roles - list indexing, and item diffing. ItemCallback handles just the second of these, which allows separation of code that indexes into an array or List from the presentation-layer and content specific diffing code.

实际上,ItemCallback只是实现方法较少,与AsyncListDiffer一起使用。这只是因为缺少的方法已经在 AsyncListDiffer 中实现了。

您必须覆盖模型的等号和哈希码 类。

RoutineModel:

class RoutineModel {
    private ArrayList<RoutineDetailModel> routineDetailModels;
    private String            routine;

    public RoutineModel(ArrayList<RoutineDetailModel> items, String routine) {
        this.routine = routine;
        this.routineDetailModels = items;
    }

    public ArrayList<RoutineDetailModel> getDetailItemList() {
        return routineDetailModels;
    }

    public int getDetailItemSize() {
        return routineDetailModels.size();
    }

    public String getRoutine() {
        return routine;
    }

    public void setRoutine(String routine) {
        this.routine = routine;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        RoutineModel that = (RoutineModel) o;
        return Objects.equals(routineDetailModels, that.routineDetailModels) &&
            Objects.equals(routine, that.routine);
    }

    @Override
    public int hashCode() {
        return Objects.hash(routineDetailModels, routine);
    }
}

RoutineDiffUtil:

public class RoutineDiffUtil extends DiffUtil.Callback {
    private final List<RoutineModel> oldRoutineList;
    private final List<RoutineModel> newRoutineList;

    public RoutineDiffUtil(ArrayList<RoutineModel> oldRoutineList, ArrayList<RoutineModel> newRoutineList) {
        this.oldRoutineList = oldRoutineList;
        this.newRoutineList = newRoutineList;
    }

    @Override
    public int getOldListSize() {
        return oldRoutineList.size();
    }

    @Override
    public int getNewListSize() {
        return newRoutineList.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldRoutineList.get(oldItemPosition).getRoutine().equals(newRoutineList.get(newItemPosition).getRoutine());
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return oldRoutineList.get(oldItemPosition).equals(newRoutineList.get(newItemPosition));
    }
}

并且不要忘记覆盖 RoutineDetailModel.

的等号和哈希码