RecyclerView局部刷新大家都遇到过,有时候还说会遇见图片闪烁的问题。

优化之前的效果:

优化之后的效果:

如果想单独更新一个item,我们通常会这样做,代码如下:

mLRecyclerViewAdapter.notifyItemChanged(position);
  • 1

这里的position就是那个列表项的索引,调用这个方法可以更新一个Item的UI(当然,你要是直接调用notifyDataSetChanged()方法也可以,但这样会造成其他不需要更新的item也会刷新)。

即便如此,图片闪烁还是出现了,什么原因引起来的呢,这里猜测可以有如下几个原因:

  1. 流传甚为广泛的一种说法,imageView的宽高不固定导致的(wrap_content)?

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

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

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

这里我们不再对上面的原因进行具体的分析,针对上面可能引起闪烁的原因进行一一验证后的结果是令人感到失望的:都不是引起图片闪烁的根本原因。

那么怎么解决这个图片闪烁的问题呢?通过查看api,我们发现了另一个方法:

重点看payload参数介绍:

payload Optional parameter, use null to identify a "full" update
  • 1

翻译过来就是如果payload参数是null,那么就会来一个“完整的”更新,也就是说会全部更新。

我们再看一下mLRecyclerViewAdapter.notifyItemChanged(position)的源码:

从源码中看到,notifyItemChanged(position)调用了 notifyItemRangeChanged(int positionStart, int itemCount)方法,源码如下:

notifyItemRangeChanged(int positionStart, int itemCount)方法最终还是调用了notifyItemRangeChanged(int positionStart, int itemCount, Object payload)方法,只是payload参数是null。

那么如果payload传一个不为null的参数,就可以实现对列表项中的具体控件更新了吗?我们通过代码验证下。

模拟更新一条数据:

这里,我们将payload参数赋值为”jdsjlzx”,当然你也可以赋值为其他值,只要不空就行。

重写adapter中的onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads)方法:

如果payloads列表不是空的,如上图所示,你就可以在else代码块里面刷新你想更新的控件了(记得不需要更新的控件就不要写在这里了)。

注意:

以上代码都是结合LRecyclerView框架来测试的,想要体验完整demo,请参考:https://github.com/jdsjlzx/LRecyclerView

总结

由此看来,RecyclerView做局部刷新还是非常容易的,其实就是使用好带payload参数的这个notifyItemChanged方法,以及重写带payload的这个onBindViewHolder方法,在onBindViewHolder中去刷新你想更新的控件即可。

PS:

拿朋友圈来说,我发一张照片,这就是一个item,但这个item里还要加上赞和评论。 
当我有评论和赞要刷新时,我需要判断当前要改动的item是否是屏幕中的可见位置。如果是,通过调用带payload参数的这个notifyItemChanged方法更新item,就能达到只刷赞或者只刷评论,而不用重新加载照片(也就是图片闪烁的原因)的效果。

怎么判断当前position是位于屏幕中呢?下面给出参考代码:

private void doAnim(int position) {
int firstItemPosition = layoutManager.findFirstVisibleItemPosition();
if (position - firstItemPosition >= 0) {
//得到要更新的item的view
View view = mRecyclerView.getChildAt(position - firstItemPosition + 1);
if (null != mRecyclerView.getChildViewHolder(view)) {
ProductsViewHolder viewHolder = (ProductsViewHolder) mRecyclerView.getChildViewHolder(view); //do something } } }

上面代码同时也获取到了ViewHolder视图,有了ViewHolder,你还可以做其他操作哦(比如item动画效果)。

再说Android RecyclerView局部刷新那个坑的更多相关文章

  1. Android RecyclerView局部刷新那个坑

    关键:public final void notifyItemChanged(int position, Object payload) RecyclerView局部刷新大家都遇到过,有时候还说会遇见 ...

  2. 安卓易学,爬坑不易—腾讯老司机的RecyclerView局部刷新爬坑之路

    前言 安卓开发者都知道,RecyclerView比ListView要灵活的多,但不可否认的里面的坑也同样埋了不少人.下面让我们看看腾讯开发工程师用实例讲解自己踩坑时的解决方案和心路历程. 话说有图有真 ...

  3. 安卓易学,爬坑不易——腾讯老司机的RecyclerView局部刷新爬坑之路

    针对手游的性能优化,腾讯WeTest平台的Cube工具提供了基本所有相关指标的检测,为手游进行最高效和准确的测试服务,不断改善玩家的体验.目前功能还在免费开放中. 点击地址:http://wetest ...

  4. RecyclerView局部刷新那点事

    1.局部刷新的引入 提到RecyclerView,我们首先想到的是ListView,对于ListView的局部刷新,我们之前已经有解决方案,[android:ListView的局部刷新]当时的解决方案 ...

  5. Android listview局部刷新和模拟应用下载(zhu)

    在android开发中,listview是比较常用的一个组件,在listview的数据需要更新的时候,一般会用notifyDataSetChanged()这个函数,但是它会更新listview中所有可 ...

  6. 转:android listview局部刷新和模拟应用下载

    在 android开发中,listview是比较常用的一个组件,在listview的数据需要更新的时候,一般会用 notifyDataSetChanged()这个函数,但是它会更新listview中所 ...

  7. RecyclerView 局部刷新(获取viewHolder 去刷新)

    RecyclerView.ViewHolder viewHolder = mRecyclerView.findViewHolderForAdapterPosition(i); if (viewHold ...

  8. RecyclerView 数据刷新的几种方式 局部刷新 notify MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  9. android:ListView的局部刷新

    1.简介 对于android中的ListView刷新机制,大多数的程序员都是很熟悉的,修改或者添加adapter中的数据源之后,然后调用notifyDataSetChanged()刷新ListView ...

随机推荐

  1. git 本地与服务器的同步

    如果在服务器上直接用 git init 则会自动在当前目录创建.git目录但在本地clone后修改后,不能push,这是由于git默认拒绝了push操作,需要进行设置,修改.git/config添加如 ...

  2. ThinkPHP3.2多域名 Virtual .htaccess 匹配 RewriteCond %{HTTP_HOST}

    <Files *> Options -Indexes </Files> <IfModule mod_headers.c> <FilesMatch " ...

  3. 在CentOS 7上安装Nginx服务器

    下面我就我在CentOS上安装Nginx经验做简单的记录,以备后查. 1.下载nginx-release包 以CentOS 7为例,下载nginx软件包:http://nginx.org/packag ...

  4. Mybatis拦截器实现SQL性能监控

    Mybatis拦截器只能拦截四类对象,分别为:Executor.ParameterHandler.StatementHandler.ResultSetHandler,而SQL数据库的操作都是从Exec ...

  5. Socket 编程IO Multiplexing

     Linux Socket 编程中I/O Multiplexing 主要通过三个函数来实现:select, poll,epoll来实现.I/O Multiplexing,先构造一张有关描述符的列表,然 ...

  6. 牛客网-《剑指offer》-重建二叉树

    题目:http://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6 C++ /** * Definition for binary ...

  7. 转:Creating a Nested ESXi 5 Environment

    http://tsmith.co/2011/creating-a-nested-esxi-5-environment/ http://tsmith.co/2012/vsphere-5-1-lab-ne ...

  8. string int 类型转换

    string  int  类型转换 (int) 此方法不适用于将string 转换为int 只能转换数值类型为int 而不能转换引用类型 不会四舍五入 直接去掉小数位 Conver.ToInt() 会 ...

  9. Oracle中的rowid

    ROWID是ORACLE中的一个重要的概念.用于定位数据库中一条记录的一个相对唯一地址值.通常情况下,该值在该行数据插入到数据库表时即被确定且唯一.ROWID它是一个伪列,它并不实际存在于表中.它是O ...

  10. java 八种基本数据类型之初始值、取值范围、对应的封装类

      CreateTime--2017年12月6日10:03:53 Author:Marydon 一.java数据类型之基本数据类型 (二)八种基本数据类型的特征 import java.math.Bi ...