Android RecyclerView With DiffUtil


前言

Android RecyclerViews几乎是所有Android应用程序的一部分。用户滚动列表和更新列表内容时,RecyclerViews列表包含大量信息。DiffUtil是一个实用程序类,用于帮助实现这一点,而使用DiffUtil的Android RecyclerView提供了这一功能。


一、DiffUtil是什么?

DiffUtil类的存在是为了提高RecyclerView在处理列表更新时的性能。即使与UI 组件相关联,您也可以在应用程序的任何部分使用它来比较相同类型的两个列表。对于这个应用程序,您需要检查两个Item类型列表之间的差异。

1.了解 DiffUtil 算法

要查看两个列表之间的差异——在RecyclerView的情况下,你已经显示的一个和你想要显示的一个(当列表中的任何项目发生变化时)—— DiffUtil使用Eugene W. Myers 差异算法. 这将计算两组元素之间的差异。

Myers 算法不处理移动的元素,因此 DiffUtil 对结果运行第二次传递,以检测哪些元素被移动。
在这里插入图片描述
此图像有两个通过网格分布的单词列表:ANDROID水平和DIORDNA垂直。

该算法计算从一个列表到另一个列表的最短路径。对角线是自由步骤,因此,它们不计入所需的迭代次数。
在这里插入图片描述
从对应于字符’A’的(0, 0)开始,Myers 算法遍历矩阵中的每个点,寻找将一个列表转换为另一个列表的最短路径。

从这个初始点,它可以下降到(0, 1),或者直接到(1, 0):

从(0, 1)可以转到(0, 2)或(1, 1)。
从(1, 0)可以到(1, 2)或(2, 0)。
在最后一个坐标(2, 0)处,有一个对角线洞察力,这意味着可以直接到达(3, 1),从而节省了几个步骤。

按照这条路径,您可以从(0, 0) → (0, 1) → (1, 0) → (3, 1)跳过(2, 0)和(3, 0)。

该算法将分析所有可能的路径,选择最短的路径将一个列表转换为另一个。在这个例子中,它需要八次迭代。

二、使用步骤

1.将 DiffUtil 添加到 ListAdapter

创建自己的 DiffUtil.Callback,定义自己的 Item 比较规则

import android.text.TextUtils;

import androidx.recyclerview.widget.DiffUtil;

import java.util.List;

public class UserDiffCallback extends DiffUtil.Callback {

    private final List<User> oldData;
    private final List<User> newData;

    public AppDiffCallback(List<User> oldData, List<User> newData) {
        this.oldData = oldData;
        this.newData = newData;
    }

    @Override
    public int getOldListSize() {
        return oldData == null ? 0 : oldData.size();
    }

    @Override
    public int getNewListSize() {
        return newData == null ? 0 : newData.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        User oldU = oldData.get(oldItemPosition);
        User newU = newData.get(newItemPosition);
        // Name
        return TextUtils.equals(oldU.getName(), newU.getName());
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        User oldU = oldData.get(oldItemPosition);
        User newU = newData.get(newItemPosition);
        // Name
        return TextUtils.equals(oldU.getName(), newU.getName());
    }
}

  1. DiffUtil.ItemCallback是负责计算两个列表之间差异的本机类。由于系统不知道要对比哪些字段,因此要覆写areItemsTheSame、areContentsTheSame。
  2. 为避免在发生更改时重新设计整个列表,仅更新两个列表之间具有不同值的项目。

2.更新数据

代码如下(示例):

private void refreshData() {
    // 新的数据源
    List < User > oldData = mAdapter.getData();
    List < User > newData = new ArrayList < > ();
    for (int i = 0; i < oldData.size(); i++) {
        newData.add(oldData.get(i).clone());
    }
    // 模拟新增数据
    newData.add(new User(6, "赵子龙"));
    // 1、计算新老数据集差异,将差异更新到Adapter
    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new UserDiffCallback(oldData,newData));
    diffResult.dispatchUpdatesTo(mAdapter);
    // 2、将新数据集设置给Adapter
	mAdapter.setData(newData);
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我可以回答这个问题。使用RecyclerViewDiffUtil可以实现对U盘中图片的加载和逐步显示。以下是示例代码: ``` public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> { private List<File> mImages; public ImageAdapter(List<File> images) { mImages = images; } @NonNull @Override public ImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false); return new ImageViewHolder(view); } @Override public void onBindViewHolder(@NonNull ImageViewHolder holder, int position) { holder.bind(mImages.get(position)); } @Override public int getItemCount() { return mImages.size(); } public void updateImages(List<File> newImages) { DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new ImageDiffCallback(mImages, newImages)); mImages.clear(); mImages.addAll(newImages); diffResult.dispatchUpdatesTo(this); } static class ImageViewHolder extends RecyclerView.ViewHolder { private ImageView mImageView; public ImageViewHolder(@NonNull View itemView) { super(itemView); mImageView = itemView.findViewById(R.id.image_view); } public void bind(File imageFile) { Glide.with(itemView.getContext()) .load(imageFile) .into(mImageView); } } static class ImageDiffCallback extends DiffUtil.Callback { private List<File> mOldImages; private List<File> mNewImages; public ImageDiffCallback(List<File> oldImages, List<File> newImages) { mOldImages = oldImages; mNewImages = newImages; } @Override public int getOldListSize() { return mOldImages.size(); } @Override public int getNewListSize() { return mNewImages.size(); } @Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { return mOldImages.get(oldItemPosition).equals(mNewImages.get(newItemPosition)); } @Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { return mOldImages.get(oldItemPosition).equals(mNewImages.get(newItemPosition)); } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值