RecyclerView + DiffUtil 使用预研

背景:RecyclerView 使用notifyDataSetChanged 会导致图片闪烁

具体原因可参看:RecyclerView 体验优化及入坑总结  的入坑篇第二个问题

一、RecyclerView 局部刷新不好用

      RecyclerView 除了配置动画、布局等方便外,相比ListView ,提供了不少数据刷新方式,除了常见的notifyDataSetChanged() 全局刷新外,还提供了很多局部刷新方式,列举如下:

图1  RecyclerView Adapter 对应刷新方式

        上述局部刷新方式,看似好用(插入、更新、移动、删除),但实际不太好用,甚至基本无用。不好用的原因在于,不知何时去选择刷新方式 ,因而还是一股脑的使用notifyDataSetChanged() ,除此之外 使用较多的场景 :页面加载更多 ,使用notifyItemRangeChanged(int ,int),替他刷新方式根本没有使用过。

       可能正因如此,Google 在 Support-v7:24:2.0 提供了DiffUtils 类,让我们正真意义上使用RecyclerView 的局部刷新。

二 、DiffUtil 介绍 及使用

        DiffUtil是 Support-v7:24:2.0 中,中更新的工具类,主要是为了配合RecyclerView使用,通过比对新、旧两个数据集的差异,生成旧数据到新数据的最小变动,然后对有变动的数据项,进行局部刷新。

   DiffUtil 核心内容 :

(1)DiffUtil.Callback  

DiffUtil.Callback  :具体用于限定数据集比对规则 ,内部主要有如下5个比较方法:

图 2 DiffUtil.Callback 

 1)getOldListSize():旧数据集的长度;

 2)getNewListSize():新数据集的长度

 3)areItemsTheSame():判断是否是同一个item;

 4)areContentsTheSame():如果item相同,此方法用于判断是否同一个 Item 的内容也相同;

图3  areContentsTheSame()

 5)getChangePayload() :如果item相同,内容不同,用 payLoad 记录这个 ViewHolder 中,具体需要更新那个View

    从图2知 ,getChangePayload() 默认返回 null ,即整个item 全部刷新。

图4  getChangePayload()

    一般在getChangePayload()方法中调用super.getChangePayload() 即可,不做精细化刷新。

     如果一个item 非常复杂,存在里面某个View 数据刷新,可以利用payLoad参数来实现,对应修改点 在 onBindViewHolder(HelloViewHolder holder, int position ) 的基础上实现带参的 onBindViewHolder ,同时在getChangedPayLoad()对应实现。

从上面分析可知:areItemsTheSame()、areContentsTheSame()、getChangePayload() 分别代表了不同量级的刷新。

(2)DiffUtil.DiffResult

DiffUtil.DiffResult : 比对数据集之后,返回的差异结果 ,通过DiffUtil.calculateDiff(diffCallback)(当数据量较大时,建议放在子线程中调用)得到。

DiffUtil.DiffResult::dispatchUpdatesTo() 根据diff 数据结果,选择刷新方式。

图5 DiffUtil.DiffResult::dispatchUpdatesTo()


 总结:使用起来比较简单 ,1)实现DiffUtil.Callback   接口 ;2)新老数据集通过DiffUtil.calculateDiff 计算得到DiffUtil.DiffResult  ;3)DiffUtil.DiffResult::dispatchUpdatesTo()  刷新数据。

三、项目使用DiffUtil遇到的问题

     在第二节中 ,已经基本介绍了DiffUtil 的使用,本节以精选页、书城等页面为例(忽略代码中边界值处理)说明 ,在使用过程中遇到的一些问题:

(1)item 判断 唯一性

       目前 ,setData ()  数据类型为  ArrayList<RowData>  (多ViewType类型)如下 ,对于item 来说 ,缺少唯一性判断属性。

图6 RowData()

       目前,使用mDisplayStyle 和id 来判断 item 是否一致。 如果item一致,则会进一步判断 item 内容是否一致(areContentsTheSame);如果item 不一致,则item 全部刷新。

图7 areItemsTheSame()

(2) areContentsTheSame() 判断过于麻烦 

   由于RowData 内 核心数据是mData (Object型),无法直接比较 实现equals ,只能在 areContentsTheSame() 内,手动实现每种ViewType 数据的equals (对象是jce协议,只能手动实现)。

手动实现的问题在于:1)jce协议新增字段,这里需要补充 ;2)新增ViewType 数据需要在这里补充;3)对应adapter 与这个callBack 关联性不大,易漏

上述三个问题,可能增加一定的维护成本

图8  areContentsTheSame

RowDataDiffCallback() 整体实现  :

图9  RowDataDiffCallback()

(3)VM 初始化 设置pullToRefreshRecycleView.setEnableLoadMore(true),导致页面滑到最下面

     目前,猜测 是加载更多模块焦点导致 (猜测未找出原因)

分析一下该问题 :pullToRefreshRecycleView.setEnableLoadMore(true) 设置本不应该在VM初始化时,设置,应该根据回包数据 的hasMore 来设置 。

直接将pullToRefreshRecycleView.setEnableLoadMore(true)  改成在回包时,调用 pullToRefreshRecycleView.setEnableLoadMore(hasMore) 上述问题解决


      上述3个问题,是我在使用diffutil中遇到的问题,在项目中可以使用,大家有空看看,还有什么疑问或改正意见。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,248评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,681评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,443评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,475评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,458评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,185评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,451评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,112评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,609评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,083评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,163评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,803评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,357评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,357评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,590评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,636评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,925评论 2 344

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,527评论 25 707
  • 这篇文章分三个部分,简单跟大家讲一下 RecyclerView 的常用方法与奇葩用法;工作原理与ListView比...
    LucasAdam阅读 4,377评论 0 27
  • 步骤1.viewDidLoad{}方法中设置监听 步骤2.在.m中添加此方法,此时已经设置结束编辑时(收起键盘时页...
    PZcoder阅读 364评论 0 0
  • 灭痘可用棉签取适量茶树精油,点在痘痘上,坚持1到3天,发红的痘痘就会变得干瘪。 新生痘印用薰衣草点涂局部,可消炎平...
    茶壶家阅读 233评论 0 0
  • 最美的黄昏应该是什么样子的? 如果是恋人,任何地方的黄昏都最美。废话了。林荫小道,山间地头,蔚蓝海岸,街心公园,人...
    田晓隐阅读 2,311评论 0 3