原文:Android RecyclerView使用ListAdapter高效刷新数据 - Stars-One的杂货小窝

我们都知道,当RecyclerView数据源更新后,还需要通过adapter调用对应的方法,从而让RecyclerView重新绘制页面

本次也是介绍了用另外一种方法来实现RecyclerView高效刷新数据的功能

问题

首先,默认各位是有使用RecyclerView的经验的,

对于数据的更新,我们一般可以使用adapter的下面四个方法:

  • notifyDataSetChanged() 整个数据改变
  • notifyItemInserted() 往某个下标插入数据,并触发动画
  • notifyItemChanged() 更新某个下标的数据,并触发动画
  • notifyItemRangeRemoved() 移除某个下标的数据,并触发动画

但是,其中下面的三个方法传参需要给个position下标,这个有时候每次由我们去计算获取,很麻烦,而且我们还要处理对应的增删改的逻辑

所以之后Android官方也是出了一个新的工具DiffUtils

DiffUtils使用

DiffUtil主要提供了一个静态方法供我们调用calculateDiff(),其中的参数为一个Callback静态抽象类,我们需要先写一个类,继承并实现其中的方法

class DiffCallBack(val oldList: ArrayList<Person>, val newList: ArrayList<Person>) :DiffUtil.Callback() {

    //判断两个对象是否相同
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return oldList[oldItemPosition].id == newList[newItemPosition].id
} override fun getOldListSize(): Int {
return oldList.size
} override fun getNewListSize(): Int {
return newList.size
} //判断两个对象内容是否相同
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val newItem = newList[newItemPosition]
val oldItem = oldList[oldItemPosition] //如果新数据和旧数据的名称和年龄相同,则视为两个item的内容相同
return oldItem.age == newItem.age && oldItem.name == newItem.name
} }

实际上,此类就是用来比较两个List的不同之处,定义区分两个同类的对象,是否相同,从上面的两个方法也是能够看得出来

首先,areItemsTheSame()方法先判断两个item是否为同个对象

这里我是选用了id作为唯一标识来区分是否为同一对象,当然,也可以用内存地址来比对,如果是内存地址来比对,则涉及浅拷贝和深拷贝的问题,这里不扩展讲解了

其次,再通过areContentsTheSame()方法来判断两个item内容是否相同

现在,我们有了一个Callback类,可以使用calculateDiff()方法了:

val oldList = adapter.getData()
//深拷贝oldList得到newList,然后对newList按照业务进行增删改的操作,这里代码就省略了.. //计算不同之处
val diffResult = DiffUtil.calculateDiff(DiffCallBack(oldList,newList))
//adapter设置新数据
adapter.setData(newList)
//将变更操作分发给adapter
diffResult.dispatchUpdatesTo(adapter)

上面给的代码可能不是太全,因为这种方法不是我们推荐的写法,更推荐使用ListAdapter来实现此功能,具体可看下文

实际上,DiffUtil算法还是耗时间的,如果数据更多,估计时间也会随之增多,所以,官方推荐开启个异步线程来处理计算,之后分发操作再切换UI线程进行数据的更新操作

ListAdapter使用

ListAdapter其实就是对上面的DiffUtil的一个封装类,以往,我们的Adapter都是继承了RecyclerView.Adapter,并在其中写了个List去装载数据,十分麻烦

ListAdapter里面维护着线程池并且还会为我们将视图修改操作移到主线程,这样我们就可以很方便的使用DiffUtil了

如果我们将此Adapter替换成继承与ListAdapter,那么都不需要我们在类中写上个List,代码示例如下:

class RvAdapter() : ListAdapter<Person, RvAdapter.ViewHolder>(diffCallback) {

    companion object {
val diffCallback = object : DiffUtil.ItemCallback<Person>() {
override fun areItemsTheSame(oldItem: Person, newItem: Person): Boolean {
return oldItem.id == newItem.id
} override fun areContentsTheSame(oldItem: Person, newItem: Person): Boolean {
//如果新数据和旧数据的名称和年龄相同,则视为两个item的内容相同
return oldItem.age == newItem.age && oldItem.name == newItem.name
} }
} class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var tvAge: TextView = itemView.findViewById(R.id.tvAge)
var tvName: TextView = itemView.findViewById(R.id.tvUserName)
} override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView = View.inflate(parent.context, R.layout.rv_item_person, null)
return ViewHolder(itemView)
} override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
holder.tvName.text = item.name
holder.tvAge.text = item.age.toString()
}
}

ListAdapter<T,ViewHolder>第一个泛型即为你的数据实体类,第二个参数为ViewHolder类

注意: 之后的数据增删改查都需要调用adapter提供的submitList()方法即可

val oldList = adapter.currentList

val newList = oldList.map { it }.toMutableList()
newList.removeAt(10)
//下标2加个新数据
newList.add(2, Person(90, "我的", 72))
adapter.submitList(list)

效果:

参考

Android RecyclerView使用ListAdapter高效刷新数据的更多相关文章

  1. Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理

    RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...

  2. Android实现RecyclerView的下拉刷新和上拉载入很多其它

    需求 先上效果图, Material Design风格的下拉刷新和上拉载入很多其它. 源代码地址(欢迎star) https://github.com/studychen/SeeNewsV2 假设对于 ...

  3. Android回到页面并刷新数据

    通过对Android Activity的生命周期的了解,需要在后退页面重写onResume()的方法. 建立自己更新数据的函数,并在onCreate()方法中调用. @Override protect ...

  4. Android Viewpager PagerAdapter update data 刷新界面数据

    最近做的项目涉及到ViewPager数据刷新,网上的资料挺多,但是和现在做的这个不太相同,所以并没有找到有效的. 折腾了大半天,整理一下思路: 问题1: 后台刷新数据次数过多后,界面出现卡顿现象,判断 ...

  5. Android RecyclerView与ListView比较

    RecyclerView 概述 RecyclerView 集成自 ViewGroup .RecyclerView是Android-support-V7版本中新增的一个Widgets,官方对于它的介绍是 ...

  6. SwipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉刷新

    下拉刷新和上拉刷新都用SwipeRefreshLayout 自带的进度条 布局 <?xml version="1.0" encoding="utf-8"? ...

  7. Android RecyclerView的基本使用

    Android RecyclerView 在去年的Google I/O大会上就推出来了,以前经常使用的ListView 继承的是AbsListView,而RecyclerView则直接继承 ViewG ...

  8. Android RecyclerView网格布局

    一个简单的网格布局activity_main.xml <?xml version="1.0" encoding="utf-8"?> <andr ...

  9. Android之SwipeRefreshLayout下拉刷新组件

    SwipeRefreshLayout概述 SwipeRefrshLayout是Google官方更新的一个Widget,可以实现下拉刷新的效果.该控件集成自ViewGroup在support-v4兼容包 ...

随机推荐

  1. 微服务性能分析|Pyroscope 在 Rainbond 上的实践分享

    随着微服务体系在生产环境落地,也会伴随着一些问题出现,比如流量过大造成某个微服务应用程序的性能瓶颈.CPU利用率高.或内存泄漏等问题.要找到问题的根本原因,我们通常都会通过日志.进程再结合代码去判断根 ...

  2. java-运算符以及简单运用

    运算符: 1)赋值运算符:= 2)算术运算符:+-*/%,++,-- 3)关系运算符:>,<,>=,<=,==,!= boolean 4)逻辑运算符:&&,|| ...

  3. OpenStack-iaas之“先点”云平台安装

    1.认识OpenStack 1.云计算的起源 早在2006年3月,亚马逊公司首先提出弹性计算云服务.2006年8月9日,谷歌公司首席执行官埃里克·施密特(Eric Schmidt)在谷歌搜索引擎大会( ...

  4. DevOps落地实践点滴和踩坑记录-(2) -聊聊平台建设

    很久没有写文章记录了,上一篇文章像流水账一样,把所见所闻一个个记录下来.这次专门聊聊DevOps平台的建设吧,有些新的体会和思考,希望给正在做这个事情的同学们一些启发吧. DevOps落地实践点滴和踩 ...

  5. day23--Java集合06

    Java集合06 13.Map接口02 13.2Map接口常用方法 put():添加 remove():根据键键删除映射关系 get():根据键获取值 size():获取元素个数 isEnpty(): ...

  6. java基础———注释

    注释是写给读者看的,并不会被执行! 单行注释 以 //开头 例如://注释内容              可以注释一行文本 多行注释 以/*开头     以 */结束 例如:/*注释内容*/      ...

  7. 08_Linux基础-vim-tmux-字符编码

    @ 目录 08_Linux基础-vim-tmux-字符编码 一. vim vim编辑器作用 vim模式 vim命令模式 vim编辑模式 vim末行模式 vim视图模式 vim替换模式 练习 vim常用 ...

  8. Ubuntu系统apt添加第三方PPA源

    一.前言 1.1目的 在使用Ubuntu时往往apt源会自带很多常用软件,但是大部分都是比较老的版本,本文主要是为了实现以下两个目的: 通过添加第三方的PPA源解决软件版本过低或者没有安装包的情况: ...

  9. Zookeeper+dubbo+Springboot集成总结

    1. 尽量用XML 集成,这也的Dubbo官方推荐的集成方式 自己在使用注解集成过程中发现有坑:Springmvc包扫描和dubbo包扫描冲突,导致消费端一直拿不到代理对象(null),非常蛋疼,所以 ...

  10. 强扩展、强一致、高可用…GaussDB成为游戏行业的心头爱

    摘要:看GaussDB for Redis强扩展.高可用.强一致.高安全,如何玩转各大游戏场景 本文分享自华为云社区<GaussDB为什么成为游戏行业的心头爱?>,作者: GaussDB ...