1.简介
DiffUtil是support-v7:24.2.0中的新工具类,它用来比较两个数据集,寻找出旧数据集-》新数据集的最小变化量,定向刷新列表。
它最大的用处就是在RecyclerView刷新时,不再使用mAdapter.notifyDataSetChanged()全部刷新,全部刷新的缺点:
- 不会触发RecyclerView的动画(删除、新增、位移、change动画)
- 性能较低,毕竟是刷新了一遍整个RecyclerView , 极端情况下:新老数据集一模一样,效率是最低的
使用DiffUtil后,改为如下代码:
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallBack(mDatas, newDatas), true);
diffResult.dispatchUpdatesTo(mAdapter);
它会自动计算新老数据集的差异,并根据差异情况,自动调用以下四个方法:
adapter.notifyItemRangeInserted(position, count);
adapter.notifyItemRangeRemoved(position, count);
adapter.notifyItemMoved(fromPosition, toPosition);
adapter.notifyItemRangeChanged(position, count, payload);
2. 例子
Bean:
public class TestBean {
private int id;
private String name;
public TestBean(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
DiffUtil.Callback: 用来比较数据集的差异
public class MyDiffUtilCallback extends DiffUtil.Callback{
private List mOldItems;
private List mNewItems;
public void setItems(@NonNull final List oldItems, @NonNull final List newItems) {
mOldItems = oldItems;
mNewItems = newItems;
}
@Override
public int getOldListSize() {
return mOldItems == null ? 0 : mOldItems.size();
}
@Override
public int getNewListSize() {
return mNewItems == null ? 0 : mNewItems.size();
}
/**
* 是否是同一个对象
*/
@Override
public boolean areItemsTheSame(final int oldItemPosition, final int newItemPosition) {
if (mOldItems.get(oldItemPosition) == null || mNewItems.get(newItemPosition) == null){
return false;
}
return mOldItems.get(oldItemPosition).getId() == mNewItems.get(newItemPosition).getId();
}
/**
* 是否是相同内容
*/
@Override
public boolean areContentsTheSame(final int oldItemPosition, final int newItemPosition) {
return mOldItems.get(oldItemPosition).getName().equals(mNewItems.get(newItemPosition).getName());
}
/**
* areItemsTheSame()返回true而areContentsTheSame()返回false时调用,也就是说两个对象代表的数据是一条,但是内容更新了。
*/
@Nullable
@Override
public Object getChangePayload(final int oldItemPosition, final int newItemPosition) {
TestBean oldBean = mOldItems.get(oldItemPosition);
TestBean newBean = mNewItems.get(newItemPosition);
//这里就不用比较核心字段了,一定相等
Bundle payload = new Bundle();
if (!oldBean.getName().equals(newBean.getName())) {
payload.putString("KEY_NAME", newBean.getName());
}
if (payload.size() == 0){
//如果没有变化 就传空
return null;
}
return payload;
}
}
DiffUtilAdapter:
public class DiffUtilAdapter extends RecyclerView.Adapter {
private List mList = new ArrayList();
private LayoutInflater mInflater;
private MyDiffUtilCallback mDiffCallback;
public DiffUtilAdapter(Context mContext) {
mDiffCallback = new MyDiffUtilCallback();
mInflater = LayoutInflater.from(mContext);
}
public void setData(TestBean mData){
mList.add(mData);
notifyItemRangeInserted(getItemCount(), 1);
}
public void setData(List mData){
mDiffCallback.setItems(mList, mData);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(mDiffCallback);
diffResult.dispatchUpdatesTo(this);
mList.clear();
mList.addAll(mData);
}
public void removeData(int index){
mList.remove(index);
notifyItemRemoved(index);
if (index != mList.size()) {
notifyItemRangeChanged(index, mList.size() - index);
}
}
public void clear(){
mList.clear();
notifyDataSetChanged();
}
@Override
@NonNull
public DiffUtilAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(mInflater.inflate(R.layout.item_test, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List