RecyclerView之DiffUtil

Catalogue   

目录

概述

使用DiffUtil的原因是替代notifyDataSetChanged,提升性能。

DiffUtil使用的是Eugene Myers的差别算法,这个算法本身不能检查到元素的移动,也就是移动只能被算作先删除、再增加,而DiffUtil是在算法的结果后再
进行一次移动检查。假设在不检测元素移动的情况下,算法的时间复杂度为O(N + D2),而检测元素移动则复杂度为O(N2)。所以,如果集合本身就已经排好序,
可以不进行移动的检测提升效率。

ListAdapter和AsyncListDiffer中有使用。

使用

1
2
3
4
5
6
7
8
9
10
11
12

public void swap(List newList) {

MyDiffCallback callback = new MyDiffCallback(oldList, newList);
DiffUtil.DiffResult result = DiffUtil.calculateDiff(callback);

oldList.clear();
oldList.addAll(newList);
result.dispatchUpdatesTo(this);
}


使用的步骤:

  1. 实现DiffUtil.Callback
  2. 调用calculateDiff计算不同点
  3. dispatchUpdatesTo刷新数据

源码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

public class DiffUtil {

//
public static DiffResult calculateDiff(@NonNull Callback cb) {
return calculateDiff(cb, true);
}

public abstract static class Callback {

// 旧数据集的长度
public abstract int getOldListSize();

// 新数据集的长度
public abstract int getNewListSize();

// 判断是否是同一个item
public abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition);

// 如果item相同,此方法用于判断是否同一个Item的内容也相同
public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition);

// 如果item相同,内容不同,用 payLoad 记录这个ViewHolder中具体需要更新那个View
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
return null;
}

}


public static class DiffResult {
// 根据diff 数据结果,选择刷新方式
public void dispatchUpdatesTo(@NonNull ListUpdateCallback updateCallback) {}

}

}

过程如下:

  1. 实现DiffUtil.Callback接口
  2. 新老数据集通过DiffUtil.calculateDiff计算得到DiffUtil.DiffResult
  3. DiffUtil.DiffResult::dispatchUpdatesTo刷新数据

参考