Android使用DiffUtil智能地更新RecyclerView
DiffUtil是一个工具类,它会找出两个列表的差异,输出一个更新列表,并且可以用来通知RecyclerView的Adapter更新。
使用
DiffUtil会使用DiffUtil.Callback来计算两个列表的差异,其中DiffUtil.Callback是一个抽象类,需要我们实现它,它包含了四个抽象方法和一个非抽象方法:
-
getOldListSize():获取旧列表的大小
-
getNewListSize():获取新列表的大小
-
areItemsTheSame(int oldItemPosition, int newItemPosition):判断新旧列表两个位置的项目是否相同
-
areContentsTheSame(int oldItemPosition, int newItemPosition):判断新旧列表两个位置的项目数据是否相同,DiffUtil只会在areItemsTheSame()返回true时才调用此方法。
-
getChangePayload(int oldItemPosition, int newItemPosition):如果areItemTheSame()返回true,而areContentsTheSame()返回false,则DiffUtil会调用此方法来获取更改后的负载
示例
模型类:Employee
public class Employee {
public int id;
public String name;
public String role;
}
实现DiffUtil.Callback
public class EmployeeDiffCallback extends DiffUtil.Callback {
private final List<Employee> mOldEmployeeList;
private final List<Employee> mNewEmployeeList;
public EmployeeDiffCallback(List<Employee> oldEmployeeList, List<Employee> newEmployeeList) {
this.mOldEmployeeList = oldEmployeeList;
this.mNewEmployeeList = newEmployeeList;
}
@Override
public int getOldListSize() {
return mOldEmployeeList.size();
}
@Override
public int getNewListSize() {
return mNewEmployeeList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return mOldEmployeeList.get(oldItemPosition).getId() == mNewEmployeeList.get(
newItemPosition).getId();
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
final Employee oldEmployee = mOldEmployeeList.get(oldItemPosition);
final Employee newEmployee = mNewEmployeeList.get(newItemPosition);
return oldEmployee.getName().equals(newEmployee.getName());
}
@Nullable
@Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
// 如果要使用ItemAnimator,可以在实现此方法
return super.getChangePayload(oldItemPosition, newItemPosition);
}
}
在RecyclerViewAdapter处理列表数据的更新
public class CustomRecyclerViewAdapter extends RecyclerView.Adapter<CustomRecyclerViewAdapter.ViewHolder> {
...
public void updateEmployeeListItems(List<Employee> employees) {
final EmployeeDiffCallback diffCallback = new EmployeeDiffCallback(this.mEmployees, employees);
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
this.mEmployees.clear();
this.mEmployees.addAll(employees);
diffResult.dispatchUpdatesTo(this); //分发更新到RecyclerView Adapter
}
}
DiffResult为计算差异后返回的结果,获取差异结果后,调用dispatchUpdatesTo(RecyclerView.Adapter)来分发更新的列表。
DiffUtil调用了RecyclerView.Adapter的以下方法来通知Adapter来更新数据集:
- notifyItemMoved()
- notifyItemRangeChanged()
- notifyItemRangeInserted()
- notifyItemRangeRemoved()