DiffUtil使用总结

最近看博客,发现了一个存在recycleview-v7包下的工具类DiffUtil,他是为recycleview的数据变化提供数据对比的工具类。
以前我们在更新数据适配器的时候,一般都是调用的mAdapter.notifyDataSetChanged(),这个是对整个列表的数据进行刷新, 调用该方法的时候并不会触发recycleview的动画,不过现在我们可以使用DiffUtil进行定向刷新,且带动画效果。
使用方法很简单

DiffUtil.DiffResult diffResult  = DiffUtil.calculateDiff(new DiffCallBack(mDataSet,
                         mNewDatas),true);
diffResult.dispatchUpdatesTo(adapter);

首先,通过DiffUtil.calculateDiff()计算新旧数据之间的差异(比较方法我们一会说)得到DiffResult ,直接通过dispatchUpdatesTo更新数据适配器,看方法名顾名思义,增量更新到数据适配器,打开这个方法我们能看到根据计算的结果,根据差异分别调用相应的刷新适配器方法,达到局部刷新

在ListUpdateCallback几个回调中分别调用以下几个方法
adapter.notifyItemRangeInserted(position, count);
adapter.notifyItemRangeRemoved(position, count);
adapter.notifyItemMoved(fromPosition, toPosition);
adapter.notifyItemRangeChanged(position, count, payload);

上面的刷新,实际上只是通过差异结果调用适配器的刷新方法改变了绑定的UI的视图,适配器中的数据依旧是原先的数据,需要我们主动去将新的数据源设置到适配器中。



下面我们来说下上文提到的比较方法,实际上我们在调用
DiffUtil.calculateDiff的时候需要传递一个参数是DiffUtil.Callback,DiffUtil.Callback是一个抽象类,有如下几个抽象方法

 //旧数据源列表大小
public abstract int getOldListSize();
//新数据源列表大小   
public abstract int getNewListSize();
//判断是否是相同的Item,在这个方法中判断两个Item是否是同一个,有ID的话可以根据ID
public abstract boolean areItemsTheSame(int      oldItemPosition, int newItemPosition);
//判断内容是否相同,这个方法只有当areItemsTheSame返回true的时候才会调用
public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition);
//这个下面再解释    
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
            return null;
        }

我们只需要继承Callback实现getOldListSize,getNewListSize,areItemsTheSame,areContentsTheSame这四个方法来比较数据。

上面讲了定向刷新,在实际上使用的时候细心的同学可能会发现如果item有一个白光一闪的动画,这个如果遇到偏着的测试可能就给你提个bug了。那有么有方法去掉这个动画呢?答案是有的。下面接着看,其中涉及到两个方法的处理
1.重写Callback的getChangePayload
2.重写适配器的onBindViewHolder(ViewHolder holder, int position, List payloads)
当getChangePayload不返回null的时候,onChange采用Partial bind,就不会出现白光一闪。
getChangePayload返回一个payloads的数据列表,onBindViewHolder中处理数据的变化更新UI
注意,在getChangePayload返回不为null的时候,适配器中调用的是带payloads参数的onBindViewHolder。 如果getChangePayload中我们比较之后没有要更新的数据,适配器中依旧是调用带payloads参数的onBindViewHolder的,在这个方法中payloads不为nul但是payloads.size为0,我们就需要手动调用不带payloads参数的onBindViewHolder。(因为我们是重写了带payloads的onBindViewHolder,基类中不处理payloads直接调用不带payloads的onBindViewHolder)。这里说的有点拗口,要了解的自己去看下源码。

你可能感兴趣的:(android,recyclevie,DiffUtil)