在android中listView/RecyclerView是最常用的ui控件,最常见的交互多是list的刷新,刷新和加载的交互涉及到adapter的刷新—-即notifyDataSetChanged()全局刷新
但是notifychaged有一些不可避免的弊端:
1.不会触发 RecyclerView 的局部更新的动画。
2.性能低,会刷新整个 RecyclerView 可视区域。
之前google有发布一个list中item局部刷新的Api:DiffUtil

DiffUtil完美解决了全局刷新的弊端;提高了UI 和data交互的效率和性能.下面 简单介绍下DiffUtil:
主要涉及两个类:
DiffUtil.Callback:具体用于限定数据集比对规则。
DiffUtil.DiffResult:比对数据集之后,返回的差异结果。

1.DiffUtil.Callback(对比新旧数据)

其中:
在 Callback 中,其实只需要实现 4 个方法:

getOldListSize():旧数据集的长度。
getNewListSize():新数据集的长度
areItemsTheSame():判断是否是同一个Item。
areContentsTheSame():如果是通一个Item,此方法用于判断是否同一个 Item 的内容也相同。

前两个是获取数据集长度的方法,这没什么好说的。但是后两个方法,主要是为了对应多布局的情况产生的,也就是存在多个 viewType 和多个 ViewHodler 的情况。首先需要使用 areItemsTheSame() 方法比对是否来自同一个 viewType(也就是同一个 ViewHolder ) ,然后再通过 areContentsTheSame() 方法比对其内容是否也相等。

其实 Callback 还有一个 getChangePayload() 的方法,它可以在 ViewType 相同,但是内容不相同的时候,用 payLoad 记录需要在这个 ViewHolder 中,具体需要更新的View。

areItemsTheSame()、areContentsTheSame()、getChangePayload() 分别代表了不同量级的刷新。

首先会通过 areItemsTheSame() 判断当前 position 下,ViewType 是否一致,如果不一致就表明当前 position 下,从数据到 UI 结构上全部变化了,那么就不关心内容,直接更新就好了。如果一致的话,那么其实 View 是可以复用的,就还需要再通过 areContentsTheSame() 方法判断其内容是否一致,如果一致,则表示是同一条数据,不需要做额外的操作。但是一旦不一致,则还会调用 getChangePayload() 来标记到底是哪个地方的不一样,最终标记需要更新的地方,最终返回给 DiffResult 。

当然,对性能要是要求没那么高的情况下,是可以不使用 getChangedPayload() 方法的。

2.DiffUtil.DiffResult(属性adapter 配合RecyclerView使用)

通过DiffUtil.Callback计算出差异然后直接作用域RecyclerView的adapter进行刷新

3代码实现

首先来看自己封装的一个RecyDiffCallback(继承自DiffUtil.Callback)

package com.example.diffutil.widget;import android.support.v7.util.DiffUtil;import java.util.List;/** * Created by houruixiang on 2017/8/21. */public class RecyDiffCallback extends DiffUtil.Callback {    private List newList;    private List oldList;    public RecyDiffCallback(List oldList, List newList) {        this.oldList = oldList;        this.newList = newList;    }    @Override    public int getOldListSize() {        return oldList.size();    }    @Override    public int getNewListSize() {        return newList.size();    }    @Override    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {        return oldList.get(oldItemPosition).getClass().equals(newList.get(newItemPosition).getClass());    }    @Override    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {        String oldStr = oldList.get(oldItemPosition);        String newStr = newList.get(newItemPosition);        return oldStr.equals(newStr);    }}

以上代码是自己封装的,在构造中传入新旧数据,然后对比data的长度,接着对比item的type是否相同;最后对比内容;
下面看MainActivity中的核心代码

@Override    public void onClick(View view) {        mOld = mData.get(index);        index++;        index = index % mData.size();        mNew = mData.get(index);        Log.i("==onClick",String.valueOf(index));        recyAdapter.setData(mData.get(index));        DiffUtil.DiffResult diffResult = DiffUtil                .calculateDiff(new RecyDiffCallback(mOld, mNew),true);        diffResult.dispatchUpdatesTo(recyAdapter);        //mList.setAdapter(recyAdapter);    }
    在代码中setData到adapter中
recyAdapter.setData(mData.get(index));
    然后进行新旧data的对比
  DiffUtil.DiffResult diffResult = DiffUtil                .calculateDiff(new RecyDiffCallback(mOld, mNew),true);

进行新旧数据集的对比 ,若三重对比(上面有介绍),然后进行diff的局部刷新:

diffResult.dispatchUpdatesTo(recyAdapter);

到这里RecyClerView+DiffUtil的局部刷新就介绍完了 是不是好用到飞起 ;
希望共同进步,欢迎大家宝贵的意见;

更多相关文章

  1. ImageView之android:tint=" "属性方法作用详解
  2. C#/IOS/Android通用加密解密方法
  3. WebView的使用之Android与JS通过WebView互调方法
  4. Android数据存储方式:SharePreference、SQLite、ContentProvider
  5. Android中数据存储----SQLite数据库
  6. Android APK文件在电脑上面运行方法
  7. 【Android】Android 多个APK数据共享
  8. 获取Android SDK 源代码并在Eclipse中关联查看的方法--转
  9. Android App开发基础篇—数据存储(SP和文件)

随机推荐

  1. google Android 认证测试
  2. 2、创建android应用程序
  3. Ubuntu下连接Android设备
  4. android PhoneGap 的入门例子
  5. android 最全的shape属性
  6. Android(安卓)之 Context Menu 上下文菜
  7. 开发Android第四步,Android NDK 及 androi
  8. 向android studio导入android源生app
  9. View组件之各xml属性
  10. AndroidStudio 备忘录之Spinner(下拉列表)