【问题标题】:(android) Can I use this code in my DiffUtill implementation?(android) 我可以在我的 DiffUtill 实现中使用此代码吗?
【发布时间】:2021-05-05 22:04:04
【问题描述】:

我现在正在创建一个 DiffUtil 类来仅更新 RecyclerView 中更改的项目。

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

比较两个对象的时候,比较的是唯一值,比如areItemsTheSame()Model(Data)类中定义的id。

不过,我觉得给List赋值id或者unique value比较困难,不然代码比较乱。

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

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

使用this是不是不仅比较对象的地址,还比较对象的内容?

作为附加问题

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);
    }
}

【问题讨论】:

    标签: java android android-diffutils


    【解决方案1】:

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

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

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

    要比较两个模型,您必须覆盖 equals()hashCode()。在那里您指定您认为两个模型相同的条件。例如,如果他们有相同的routine。我不知道你的任务的上下文,所以我不能确切地告诉你如何实现它们,但通常你只是比较所有字段。可能添加一个id 字段也是一个好主意。如果它们具有相同的id,那么您可以认为模型“相等”。在hashCode() 中,您可以返回Objects.hash(id)

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

    DiffUtil.Callback 有两个角色 - 列表索引和项目差异。 ItemCallback 只处理其中的第二个,它允许将索引到数组或列表中的代码与表示层和内容特定的差异代码分开。

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

    【讨论】:

    • 感谢您的详细回答。但是我能问你几个问题吗? 1. 第三段中,Previous Callback 是指 areItemsTheSame() 吗? 2.视觉表示是什么意思?我不知道如何理解这个词的意思。 3. 如果我在代码中覆盖两个对象的相等比较时不使用id,我可以用例程字符串进行相等比较吗?没有必要比较所有成员,对吧?
    • 1.是的。 2. 这意味着你想重绘你的列表项。例如。您通过id 比较项目,它是相同的,但您也有一个字段routine,它已被更改。因此,项目相同,但内容不同。 3. 是的,没错。但是想想你的产品的逻辑。 routine 每个型号真的是独一无二的吗?如果不是,那么您将遇到问题:某些列表项看起来相同,但实际上却不同
    • 但是,在将hashCode与例程进行比较时,即使例程不是唯一的并返回true,areContentsTheSame()也会比较内容(例程、routineDetailModels),所以没关系??
    • 它只会影响动画——“改变”动画而不是“创建和删除”动画
    • 非常感谢。 :)
    【解决方案2】:

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

    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 的等号和哈希码。

    【讨论】:

    • 谢谢。但是hashCode() 在你的代码中调用了什么?
    • 你的意思是也覆盖RoutineDetailModel的equals和hashcode?​​span>
    • 将元素添加到Hash 结构时使用哈希码以便轻松找到它们。始终建议同时覆盖它们。是的,您也必须为您的 RoutineDetailModel 覆盖它们,因此如果某些参数已更改,则对 areContentsTheSame 的检查可能会返回 false。
    • 那么,RoutineDetail 是否也可以像例程一样覆盖 equals()hashCode()
    • 是的,可以,而且应该
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2015-07-27
    • 1970-01-01
    • 2019-04-20
    • 1970-01-01
    • 2015-11-03
    相关资源
    最近更新 更多