RecycleView局部刷新闪动的问题

腾讯老司机的RecyclerView局部刷新爬坑之路

转载 2016年10月21日 16:15:18
  • 2671
  • 编辑
  • 删除



作者:Hoolly,腾讯移动客户端开发工程师。 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处
WeTest导读安卓开发者都知道,RecyclerView比ListView要灵活的多,但不可否认的里面的坑也同样埋了不少人。下面让我们看看腾讯开发工程师用实例讲解自己踩坑时的解决方案和心路历程。 话说有图有真相,首先来对比一下局部刷新前后的效果:

优化之前的效果:



优化之后的效果:

RecycleView局部刷新闪动的问题_第1张图片

可以看到,优化之后,列表中的这张大图不在有一闪一闪亮晶晶的效果了!

那么,这是如何做到的呢?这是本文的重点,本文的大纲主要包括:
  1. 分析为什么会闪一下

  2. 对分析的可能造成闪动的问题进行解决

  3. 验证是否解决


 一、为什么会闪一下?

我们的需求是大家已经看到了,点击打分,弹出一个对话框,点击一个分数,这时候,通过一些列复杂的转换(当然不是本文的论述的重点),这时候到了要更新列表项了,如是很自然,我们会这么做:


因为,操作的那个列表项你是知道他的position,所以你可以这么做,(当然,我之前是直接notifyDataSetChanged的,这个会照成所以不不要的item也会刷新)然而,闪动还是出现了,那么我开始怀疑:
  1. 流传甚为广泛的一种说法,imageView的宽高不固定导致的(wrap_content)?

  2. 这个是RecyclerView自带的更新动画效果导致的?

  3. 这个是因为图片加载框架(glide 的 animte)的动画效果导致的?

  4. getView中(RecyclerView中是onBindViewHolder)加载图片的时候,设置一个tag,当发现这个imageView的tag和之前的tag一致时就不加载



二、带着思考,就去尝试吧!

1、对于第一种,我的做法是自己写了一个自定义的imageView,重写omMeasure方法,如下:

RecycleView局部刷新闪动的问题_第2张图片

因为我们的这个列表项中的图片是(高=宽)的,因此,我才这么写,这样写也有一个好处,不用在onBindViewHolder中去动态的计算出高度,然后在已layoutParm的方式设置给imageView,相信不少小伙伴都做过了吧!

然而,遗憾的是,他并没有解决闪一下的问题!此时这个闪动的原因显然不在这里,但是这里做的,可以保留下来。


2、对于第二种说法,我参考了这里 http://stackoverflow.com/questions/29331075/recyclerview-blinking-after-notifydatasetchanged

的做法:

RecycleView局部刷新闪动的问题_第3张图片

以及也尝试了这种


然而,那种渐变的闪动消失了,但是,取而代之的是一种更加不可接受的闪动,这里就不用gif展示了,因此原因也并不在此处。


3、对于对三种说法,我也去尝试了一下将glide加载改为:


然而得到的依然是一个失望的结果,依然没有解决闪动的问题,原因也不在此处。


4、那么,就剩下最后一个猜测了,那么会不会是它呢?那就试试吧,于是代码改为:

RecycleView局部刷新闪动的问题_第4张图片

这里的做法其实就是设置Tag,那么是骡子是马,拉出来溜溜吧,结果更加令人发指,如图:

RecycleView局部刷新闪动的问题_第5张图片


好吧,此时已经有点崩溃了,显然这个也不是我要的结果,那么此时是否应该在静下来想一想,自己对于可能的几种原因做过的一些对策,是否有哪里遗漏了。经过思考,发现并没有!!那么一定是还有其他的原因,没有考虑到!

还是去翻一翻RecyclerView的api吧,我注意到了这个api:

RecycleView局部刷新闪动的问题_第6张图片

RecycleView局部刷新闪动的问题_第7张图片

可以看到这里有一个payload的参数,use null to identify a “full” update这是说如果传null就是全部更新,回过头去看一看我们之前的调用方式:

看一下源码,发现

RecycleView局部刷新闪动的问题_第8张图片

实际上,payload这个参数就是传的null,那也就是说如果传一个不为null的参数,就可以对列表项中的具体控件更新了?

http://stackoverflow.com/questions/33176336/need-an-example-about-recyclerview-adapter-notifyitemchangedint-position-objec

我了解到这个方法的使用方式是这样的:

RecycleView局部刷新闪动的问题_第9张图片

然来,onBindViewHolder有这么一个重载方式,如是我也这么做了,在下面这个重载中,去更新我想更新的控件:

RecycleView局部刷新闪动的问题_第10张图片

然后,更新的方式变成了这种:


是骡子是马,那就在遛一遛吧!

然而,依然是会闪一下!!!这这么会!!!还是调试一下吧,新重载onBindViewHolder方法有没有被执行,一更代码,发现果然没有被执行! 那么,究竟是什么鬼?去网上查了一下,有人给出了一个解决办法:

http://stackoverflow.com/questions/32463136/recyclerview-adapter-notifyitemchanged-never-passes-payload-to-onbindviewholde

RecycleView局部刷新闪动的问题_第11张图片

需要重写这个动画,让永远返回true,已达到newHolder和olderHolder是同一个,然而,这真的就是我的救命稻草吗?


那么,是骡子是马,拉出来溜溜吧,然而,并不是马!!进源码看一看

RecycleView局部刷新闪动的问题_第12张图片

发现其实只要我们传入的payload不为空,那么返回的就是true?重写有意义吗?显然,我重载的onBindViewHolder方法并没有执行的原因显然不是这个。

那么,到底,到底问题出在何处?会不会是XrecyclerView的问题?根据调用栈,我看到第一个onBindViewHolder被执行了,往上面跟,发现XrecyclerView的实现果然存在问题!


RecycleView局部刷新闪动的问题_第13张图片

如图,作者仅仅只实现了,不带payload的方法,最后adapter调用的只有不带paylaod的方法!所以,重写一个吧!


RecycleView局部刷新闪动的问题_第14张图片

最后!终于达到了想要的效果了,经过这次爬坑,选择一个开源的框架真滴是需要慎重再慎重。

总结

实际上RecyclerView做局部刷新是非常容易的,其实就是使用好带payload参数的这个notifyItemRangeChanged方法,以及override带payload的这个onBindViewHolder方法,在onBindViewHolder中去刷新你想更新的控件即可,并非是网上传闻的那些原因,当然此处爬坑时间之长,也可能更选用开源控件不当有关,所以,选择开源控件,要谨慎再谨慎!


作者:Hoolly,腾讯移动客户端开发工程师。 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处
WeTest导读安卓开发者都知道,RecyclerView比ListView要灵活的多,但不可否认的里面的坑也同样埋了不少人。下面让我们看看腾讯开发工程师用实例讲解自己踩坑时的解决方案和心路历程。 话说有图有真相,首先来对比一下局部刷新前后的效果:

优化之前的效果:



优化之后的效果:

RecycleView局部刷新闪动的问题_第15张图片

可以看到,优化之后,列表中的这张大图不在有一闪一闪亮晶晶的效果了!

那么,这是如何做到的呢?这是本文的重点,本文的大纲主要包括:
  1. 分析为什么会闪一下

  2. 对分析的可能造成闪动的问题进行解决

  3. 验证是否解决


 一、为什么会闪一下?

我们的需求是大家已经看到了,点击打分,弹出一个对话框,点击一个分数,这时候,通过一些列复杂的转换(当然不是本文的论述的重点),这时候到了要更新列表项了,如是很自然,我们会这么做:


因为,操作的那个列表项你是知道他的position,所以你可以这么做,(当然,我之前是直接notifyDataSetChanged的,这个会照成所以不不要的item也会刷新)然而,闪动还是出现了,那么我开始怀疑:
  1. 流传甚为广泛的一种说法,imageView的宽高不固定导致的(wrap_content)?

  2. 这个是RecyclerView自带的更新动画效果导致的?

  3. 这个是因为图片加载框架(glide 的 animte)的动画效果导致的?

  4. getView中(RecyclerView中是onBindViewHolder)加载图片的时候,设置一个tag,当发现这个imageView的tag和之前的tag一致时就不加载



二、带着思考,就去尝试吧!

1、对于第一种,我的做法是自己写了一个自定义的imageView,重写omMeasure方法,如下:

RecycleView局部刷新闪动的问题_第16张图片

因为我们的这个列表项中的图片是(高=宽)的,因此,我才这么写,这样写也有一个好处,不用在onBindViewHolder中去动态的计算出高度,然后在已layoutParm的方式设置给imageView,相信不少小伙伴都做过了吧!

然而,遗憾的是,他并没有解决闪一下的问题!此时这个闪动的原因显然不在这里,但是这里做的,可以保留下来。


2、对于第二种说法,我参考了这里 http://stackoverflow.com/questions/29331075/recyclerview-blinking-after-notifydatasetchanged

的做法:

RecycleView局部刷新闪动的问题_第17张图片

以及也尝试了这种


然而,那种渐变的闪动消失了,但是,取而代之的是一种更加不可接受的闪动,这里就不用gif展示了,因此原因也并不在此处。


3、对于对三种说法,我也去尝试了一下将glide加载改为:


然而得到的依然是一个失望的结果,依然没有解决闪动的问题,原因也不在此处。


4、那么,就剩下最后一个猜测了,那么会不会是它呢?那就试试吧,于是代码改为:

RecycleView局部刷新闪动的问题_第18张图片

这里的做法其实就是设置Tag,那么是骡子是马,拉出来溜溜吧,结果更加令人发指,如图:

RecycleView局部刷新闪动的问题_第19张图片


好吧,此时已经有点崩溃了,显然这个也不是我要的结果,那么此时是否应该在静下来想一想,自己对于可能的几种原因做过的一些对策,是否有哪里遗漏了。经过思考,发现并没有!!那么一定是还有其他的原因,没有考虑到!

还是去翻一翻RecyclerView的api吧,我注意到了这个api:

RecycleView局部刷新闪动的问题_第20张图片

RecycleView局部刷新闪动的问题_第21张图片

可以看到这里有一个payload的参数,use null to identify a “full” update这是说如果传null就是全部更新,回过头去看一看我们之前的调用方式:

看一下源码,发现

RecycleView局部刷新闪动的问题_第22张图片

实际上,payload这个参数就是传的null,那也就是说如果传一个不为null的参数,就可以对列表项中的具体控件更新了?

http://stackoverflow.com/questions/33176336/need-an-example-about-recyclerview-adapter-notifyitemchangedint-position-objec

我了解到这个方法的使用方式是这样的:

RecycleView局部刷新闪动的问题_第23张图片

然来,onBindViewHolder有这么一个重载方式,如是我也这么做了,在下面这个重载中,去更新我想更新的控件:

RecycleView局部刷新闪动的问题_第24张图片

然后,更新的方式变成了这种:


是骡子是马,那就在遛一遛吧!

然而,依然是会闪一下!!!这这么会!!!还是调试一下吧,新重载onBindViewHolder方法有没有被执行,一更代码,发现果然没有被执行! 那么,究竟是什么鬼?去网上查了一下,有人给出了一个解决办法:

http://stackoverflow.com/questions/32463136/recyclerview-adapter-notifyitemchanged-never-passes-payload-to-onbindviewholde

RecycleView局部刷新闪动的问题_第25张图片

需要重写这个动画,让永远返回true,已达到newHolder和olderHolder是同一个,然而,这真的就是我的救命稻草吗?


那么,是骡子是马,拉出来溜溜吧,然而,并不是马!!进源码看一看

RecycleView局部刷新闪动的问题_第26张图片

发现其实只要我们传入的payload不为空,那么返回的就是true?重写有意义吗?显然,我重载的onBindViewHolder方法并没有执行的原因显然不是这个。

那么,到底,到底问题出在何处?会不会是XrecyclerView的问题?根据调用栈,我看到第一个onBindViewHolder被执行了,往上面跟,发现XrecyclerView的实现果然存在问题!


RecycleView局部刷新闪动的问题_第27张图片

如图,作者仅仅只实现了,不带payload的方法,最后adapter调用的只有不带paylaod的方法!所以,重写一个吧!


RecycleView局部刷新闪动的问题_第28张图片

最后!终于达到了想要的效果了,经过这次爬坑,选择一个开源的框架真滴是需要慎重再慎重。

总结

实际上RecyclerView做局部刷新是非常容易的,其实就是使用好带payload参数的这个notifyItemRangeChanged方法,以及override带payload的这个onBindViewHolder方法,在onBindViewHolder中去刷新你想更新的控件即可,并非是网上传闻的那些原因,当然此处爬坑时间之长,也可能更选用开源控件不当有关,所以,选择开源控件,要谨慎再谨慎!





$(".MathJax").remove();




阅读全文

          
yx284853845love

再说Android RecyclerView局部刷新那个坑

  • jdsjlzx
  • jdsjlzx
  • 2016年10月22日 17:06
  • 28866
关键:public final void notifyItemChanged(int position, Object payload)RecyclerView局部刷新大家都遇到过,有时候还说会遇见图...

android recycleView局部刷新的选择

  • gan303
  • gan303
  • 2016年07月28日 14:58
  • 5810
android中recycleview的运用随着android系统的更新以及手机硬件的更新迭代,已经越来越广泛。

而其中的局部刷新便是许多需求都要求实现的基础功能。
那么对于如何局部刷新而言。方式一般…

                

RecyclerView的局部刷新

  • u012790961
  • u012790961
  • 2015年11月12日 21:15
  • 9258
一直纠结于RecyclerView的局部刷新,终于解决了.

因为要实现的效果要不断地去刷新item中的某些控件数据
所以使用notifydatachangedset(),notifyitemdat…

                

Recylerview局部刷新

  • qq541976141
  • qq541976141
  • 2016年05月23日 23:29
  • 633
Recylerview局部刷新

RecycleView局部刷新

  • wjt_developer
  • wjt_developer
  • 2016年11月27日 21:17
  • 213
有时候我们需要用RecycleView来展示网络数据,如果做了加载更多功能,那么我们调用传统的notifyDataSetChanged方法,必然会刷新全部的Item,既耗内存,又耗流量(假如没有缓存)...

RecyclerView局部刷新的应用场景简单分析

  • Captive_Rainbow_
  • Captive_Rainbow_
  • 2017年05月09日 09:08
  • 946
RecyclerView 局部刷新的应用场景巩固今天在做通讯录屏蔽时,由于通讯录列表里有两种不同的效果展示:1. 已经屏蔽的 item ,显示一个按钮“解除屏蔽”

2. 未屏蔽的 item ,显示两个…

                

android RecyclerView局部刷新

  • qq15357971925
  • qq15357971925
  • 2017年09月20日 17:29
  • 1850
项目中列表需要有点赞的功能,这时我们想到RecyclerView比listview的好处就是,recyclerview有单条item刷新的方法,于是就调用了RecyclerView的notifyIte...

Android RecyclerView更新某条/一条数据

  • jdsjlzx
  • jdsjlzx
  • 2016年01月01日 17:30
  • 12018
注意:使用notifyItemRemoved(position)更新数据之前,还必须集合中删除该数据:mDatas.remove(position),否则不更新。

更新数据 

这里更新数据集不…

                

RecyclerView局部刷新的坑

  • professionIT
  • professionIT
  • 2016年10月21日 18:51
  • 10070
话说有图有真相,首先来对比一下局部刷新前后的效果:

优化之前的效果:

优化之后的效果:

可以看到,优化之后,列表中的这张大图不在有一闪一闪亮晶晶的效果了!

那么,这是如何做到的呢?这是本…

                

ListView/RecyclerView的item中有进度条的处理

之所以特意提出是有进度条的情况,是因为进度条刷新的频率非常高,如果是在进度刷新的时候调用notifyDataSetChanged或者notifyItemChanged方法虽然可以实现刷新,但是界面会频...
  • u014583590
  • u014583590
  • 2016年08月06日 11:10
  • 3435

Recyclerview刷新延迟的问题(刷新两次才更新数据)

最近闲来开发一个自己游戏公会的小应用,成员介绍模块的实现用到了Recyclerview,从后台获取成员的详细信息然后Recyclerview展示。实现下拉刷新数据时,遇到了一个问题:后台数据更新后,下...
  • cumtsx
  • cumtsx
  • 2016年07月05日 21:31
  • 3463

RecyclerView使用、上拉加载、局部刷新、多种布局、点击事件和坑

一、Recycler的基础使用先来了解一下它是干啥的:

可以实现ListView的效果
可以实现GridView的效果
可以实现瀑布流的效果
主要是通过设置它的setLayoutManager来决…

                    
  • hello_1s
  • hello_1s
  • 2017年01月06日 12:25
  • 2981

解决RecyclerView局部刷新时闪烁

  • CSDN_LQR
  • CSDN_LQR
  • 2017年01月04日 19:42
  • 4149
RecyclerView局部刷新是由于其自带的item动画造成的,相信都看过RecyclerView在移除某个item时的删除动画吧,这个闪烁也是默认动画中的效果,所以只要去掉默认动画里的闪烁效果问题...

RecyclerView列表数据刷新

  • lzq520210
  • lzq520210
  • 2017年04月05日 14:38
  • 474
需求是这样的,一个RecyclerView列表数据,每一个item都有点赞功能,点击item进入详情页,详情页也可以点赞,在详情页点赞后,返回列表,要求刷新数据,是刷新某一个item的数据,不是所有的...

关于RecyclerView刷新

  • sunyuntai
  • sunyuntai
  • 2016年12月31日 11:40
  • 643
用SwipeRefreshLayout嵌套Recycler

下面是布局文件
 
        android:id=”@+id/swipeRefreshLayout”
        androi…

                

添加或删除RecyclerView的item后 刷新Adapter中的数据源的个数

通常Recycler给Adapter赋上数据源的时候利用:adapter.notifyDataSetChanged();这样一般是在初始化界面 从网络获取到数据后 直接赋给adapter的写法。然后再...
  • zhangli_
  • zhangli_
  • 2017年04月13日 10:12
  • 2773

Recyclerview使用notifyitemchanged方法会回到顶部

categories.get(lastPosition).setSelected(false);

categoryAdapter.notifyItemChanged(lastPosition);
ca…

                    
  • b14858856
  • b14858856
  • 2016年10月25日 11:28
  • 3974

RecyclerView局部更新

  • jimdaxu
  • jimdaxu
  • 2018年03月16日 15:58
  • 24
局部更新两个步骤:1 mAdapter.notifyItemChanged(position);2 重写adapter中的onBindViewHolder(RecyclerView.ViewHolde...

Android框架之路——Glide加载图片(结合RecyclerView、CardView)

Android框架之路——Glide加载图片(结合RecyclerView、CardView)一、简介:

在泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide 的图片加载库,作者是b…

                    
  • bskfnvjtlyzmv867
  • bskfnvjtlyzmv867
  • 2017年05月03日 01:42
  • 4258

Android——实现酷炫的RecyclerView心形交错下拉刷新动画

最近好久没发博客了啊...虽然工作比较忙,但还是懈怠了。

本文介绍实现的一个带动效的RecyclerView下拉刷新动画,效果如下图:
 

实现原理:
基于Aspsine的上拉加载下拉刷新的Rec…

                    
  • qq_22770457
  • qq_22770457
  • 2017年01月08日 16:31
  • 2495


等级:
3级,点击查看等级说明
访问量: 3万+
积分: 536
排名: 9万+
// 判断并设置用户名位置,没有博客专家与关注按钮时,用户名居中 medalschildren= m e d a l s c h i l d r e n = ('.medals').children().length; spanaddfollow= s p a n a d d f o l l o w = ('#span_add_follow').length; if( medals_children === 0 && medals_children === 0 && span_add_follow === 0){ $('.inf_bar dd').css('vertical-align','10px') }
                

文章分类

展开

博主热门文章



  • Android环信EaseUI的快速集成
    5570


  • Lambda 出现Cannot get property ‘destinationDir’ on null object错误提示
    2831


  • Android百度地图集成后只显示网格不显示地图问题
    2739


  • 腾讯老司机的RecyclerView局部刷新爬坑之路
    2653


  • 修改手机状态栏字体的颜色(如:白底黑字)
    2544


  • 一个Activity中多个Fragment实现沉浸式状态栏
    2254


  • Lombok添加@AllArgsConstructor后报错“错误:找不到符号 符号:类 ConstructorProperties ”
    1934


  • Google的Vysor使用时出现黑屏解决
    1526


  • ButterKnife If this view is optional add ‘@Nullable’ (fields) or ‘@Optional’ (methods) annotation
    1479


  • Android:get/set setting for user asks to run as user -2 but is calling from user 0
    1099













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