RecyclerView网络图像刷新会闪烁

1.前言


最近将Glide3.8升级到4.0,除了使用上有细微的调整,过渡还是很流畅的。但是在替换完,并体验到新特性带来的便利后,测试反馈了个现象,标记为Bug让修复。以下记录分析问题和解决问题的过程,希望对大家有一定的帮助。若有更好的方法,欢迎在评论中指出,大家共同探讨。

2.常见现象


界面很简单就不上图了,大概描述一下。一个横向的RecyclerView中展示一堆Item,每个Item分别包含纵向排布的圆形头像和名字。根据用户的操作,会向其中添加、删除和更新某些或某个Item。由于是对数据操作,肯定得刷新RecyclerView的Adapter。这时,会导致Item先显示底色或占位图,再渐显地加载图像。

Glide.png

由于官方给出说明,有三种圆形ImageView会与Glide的方法产生问题,建议使用BitmapTransformation,或.dontAnimate()取消加载过渡动画,又或者4.0中的.circleCrop()裁剪图像。本人亲测,谷歌官方v4包中的RoundedBitmapDrawable也是支持Glide的,不知道的同学可以参考小菜希的Blog

然而,在按文档修改完后,问题仍然出现了。这是什么原因呢?仅仅只是升级Glide,并没有改变业务逻辑啊,难道是新版Glide的原因。排除自己使用错了,不可能还原回去,指望着它的新特性解决问题呢。

3.解决方案


经过向谷歌询问N遍,发现很可能是RecyclerView的使用姿势不对。就几种常见情况给大家分析一下:

3.1.全局刷新

当你使用.notifyDataSetChanged()刷新列表时,会更新所有的数据。耗资源不说,关键是整个界面图像重新加载,给用户莫名其妙的感觉,影响体验和心情。

都知道RecyclerView的Item是可以复用,但是如何复用,可能就不大清楚了。每个Item被复用是随机的,它移出屏幕外被回收后,等待再次使用。全局刷新,会让回收的Item加载内容,没回收的可能内容被别的Item先加载了,只能回收后加载。一瞬间Item的位置全乱了,都得重新加载内容,尤其图像加载较慢,你就感觉整个世界胡乱地闪了一下。

知道原因,想解决就不难了。给每个Item一个固定的ID,刷新时与位置对应,别瞎跑就可以了。重写Adapter的getItemId(int position)方法,返回position作为ID,然后再设置Adapter的setHasStableIds(true)即可。

3.2.局部刷新

对RecyclerView了解比较多的人都知道,它的Adapter新增了不少局部刷新的方法,具体如下:

  • notifyItemChanged(int position) 更新列表position位置上的数据时调用,伴有渐变动画效果
  • notifyItemInserted(int position) 列表position位置添加一条数据时调用,伴有动画效果
  • notifyItemRemoved(int position) 列表position位置移除一条数据时调用,伴有动画效果
  • notifyItemMoved(int fromPosition, int toPosition) 列表fromPosition位置的数据移到toPosition位置时调用,伴有动画效果
  • notifyItemRangeChanged(int positionStart, int itemCount) 列表从positionStart位置到itemCount数量的列表项进行数据刷新,伴有渐变动画效果
  • notifyItemRangeInserted(int positionStart, int itemCount) 列表从positionStart位置到itemCount数量的列表项批量添加数据时调用,伴有动画效果
  • notifyItemRangeRemoved(int positionStart, int itemCount) 列表从positionStart位置到itemCount数量的列表项批量删除数据时调用,伴有动画效果

使用局部刷新解决了Item错乱的问题,并且减少了额外的资源消耗,可是闪烁仍然存在。只不过导致的原因变了,是由于渐变动画效果增加了展示图像的时间。所以解决方法也很简单,就是取消或屏蔽过渡动画。提供两种常用的方法供大家参考:

// 第一种,直接取消动画
ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
  ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
// 老版本的支持库
recyclerView.getItemAnimator().setSupportsChangeAnimations(false);

// 第二种,设置动画时间为0
recyclerView.getItemAnimator().setSupportsChangeAnimations(false);

4.性能优化


若你觉得解决问题就完了,那么下面的可以不用看了。

细心的朋友会发现RecyclerView的Adapter还有一个方法没有讲,那就是notifyItemChanged(int position, Object payload)。payload对象有啥用?怎么用?别着急,听我慢慢道来。

当你只想对Item中的名字进行更改,那么刷新Item会重复加载图像,哪怕已经缓存了,可毕竟还是消耗资源。如何才能仅仅更新Item中的某一项嘞,方法是有的。刷新其实是调用Adapter的onBindViewHolder(RecyclerView.ViewHolder holder, int position)方法,当你重写时会发现还有一个类似的方法onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads),现在知道payload对象是干嘛用的了吧。你可以在重写时对payload进行判断,从而更新Item中不同的项,枚举类型是个不错的选择。

5.总结


主要的都讲完了,通过这篇文章反映了解决问题的思路,希望能对大家有所启发。最后,忍不住偷偷透露一下,若你想同时进行增加、移动和修改,并且都得带上动画咋办?谷歌Support Library提供了DiffUtil工具类来比较每一项的变化,真是良心之作,还不知道的点击这里

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

推荐阅读更多精彩内容