前言
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());
}
}
- DiffUtil.ItemCallback是负责计算两个列表之间差异的本机类。由于系统不知道要对比哪些字段,因此要覆写areItemsTheSame、areContentsTheSame。
- 为避免在发生更改时重新设计整个列表,仅更新两个列表之间具有不同值的项目。
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);
}