本文由张旭童投稿。
张旭童的博客 概述DiffUtil是support-v7:4..0中的新工具类,它用来比较两个数据集,寻找出旧数据集-》新数据集的最小变化量。
说到数据集,相信大家知道它是和谁相关的了,就是我的最爱,RecyclerView。
就我使用的这几天来看,它最大的用处就是在RecyclerView刷新时,不再无脑mAdapter.notifyDataSetChanged()。
以前无脑mAdapter.notifyDataSetChanged()有两个缺点:
不会触发RecyclerView的动画(删除、新增、位移、change动画)
性能较低,毕竟是无脑的刷新了一遍整个RecyclerView,极端情况下:新老数据集一模一样,效率是最低的。
使用DiffUtil后,改为如下代码:
DiffUtil.DiffResultdiffResult=DiffUtil.calculateDiff(newDiffCallBack(mDatas,newDatas),true);diffResult.dispatchUpdatesTo(mAdapter);
它会自动计算新老数据集的差异,并根据差异情况,自动调用以下四个方法
adapter.notifyItemRangeInserted(position,count);adapter.notifyItemRangeRemoved(position,count);adapter.notifyItemMoved(fromPosition,toPosition);adapter.notifyItemRangeChanged(position,count,payload);
显然,这个四个方法在执行时都是伴有RecyclerView的动画的,且都是定向刷新方法,刷新效率蹭蹭的上升了。
老规矩,先上图,
图一是无脑mAdapter.notifyDataSetChanged()的效果图,可以看到刷新交互很生硬,Item突然的出现在某个位置:
图二是使用DiffUtils的效果图,最明显的是有插入、移动Item的动画:
转成GIF有些渣,下载文末Demo运行效果更佳哦。
本文将包含且不仅包含以下内容:先介绍DiffUtil的简单用法,实现刷新时的“增量更新”效果。(“增量更新”是我自己的叫法)
DiffUtil的高级用法,在某项Item只有内容(data)变化,位置(position)未变化时,完成部分更新(官方称之为Partialbind,部分绑定)。
了解到RecyclerView.Adapter还有publicvoidonBindViewHolder(VHholder,intposition,ListObjectpayloads)方法,并掌握它。
4在子线程中计算DiffResult,在主线程中刷新RecyclerView。
5少部分人不喜欢的notifyItemChanged()导致Item白光一闪的动画如何去除。
6DiffUtil部分类、方法官方注释的汉化
DiffUtil的简单用法前文也提到,DiffUtil是帮助我们在刷新RecyclerView时,计算新老数据集的差异,并自动调用RecyclerView.Adapter的刷新方法,以完成高效刷新并伴有Item动画的效果。这里需要读者脑补一个简单的RecyclerView展示列表的代码,当然还有个按钮点击模拟刷新。
ok,脑补成功,继续...
下面开始进入正题,简单使用DiffUtil,我们需要且仅需要额外编写一个类。想成为文艺青年,我们需要实现一个继承自DiffUtil.Callback的类,实现它的四个abstract方法。
虽然这个类叫Callback,但是把它理解成:定义了一些用来比较新老Item是否相等的契约(Contract)、规则(Rule)的类,更合适。
DiffUtil.Callback抽象类如下:
本Demo如下实现DiffUtil.Callback,核心方法配有中英双语注释(说人话就是,翻译了官方的英文注释,方便大家更好理解)。
注释张写了这么详细的注释+简单的代码,相信一眼可懂。然后在使用时,注释掉你以前写的notifyDatasetChanged()方法吧,替换成以下代码:
讲解:步骤一在将newDatas设置给Adapter之前,先调用DiffUtil.calculateDiff()方法,计算出新老数据集转化的最小更新集,就是DiffUtil.DiffResult对象。DiffUtil.calculateDiff()方法定义如下:第一个参数是DiffUtil.Callback对象,第二个参数代表是否检测Item的移动,改为false算法效率更高,按需设置,我们这里是true。
publicstaticDiffResultcalculateDiff(Callbackcb,booleandetectMoves)
步骤二
然后利用DiffUtil.DiffResult对象的dispatchUpdatesTo()方法,传入RecyclerView的Adapter,替代普通青年才用的mAdapter.notifyDataSetChanged()方法。查看源码可知,该方法内部,就是根据情况调用了adapter的四大定向刷新方法。
小结:所以说,DiffUtil不仅仅只能和RecyclerView配合,我们也可以自己实现ListUpdateCallback接口的四个方法去做一些事情。(我暂时不负责任随便一想,想到可以配合自己项目里的九宫格控件?或者优化我上篇文章写的NestFullListView?小安利,见ListView、RecyclerView、ScrollView里嵌套ListView相对优雅的解决方案:白癜风医院地址北京哪里治疗白癜风便宜