Android RecyclerView使用ListAdapter高效刷新数据
我们都知道,当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)
效果:

参考
- 别再notifyDataSetChanged()了!使用DiffUtil让你的RecyclerView更加丝滑 - 掘金
- 拒绝手动Notifydatasetchanged(),使用ListAdapter高效完成RecyclerView刷新 - 掘金
- Android高性能列表:RecyclerView + DiffUtil - 知乎
- Android中DiffUtil的使用详解 Android开发之DiffUtil的使用详解(IT技术)
Android RecyclerView使用ListAdapter高效刷新数据的更多相关文章
- Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理
RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...
- Android实现RecyclerView的下拉刷新和上拉载入很多其它
需求 先上效果图, Material Design风格的下拉刷新和上拉载入很多其它. 源代码地址(欢迎star) https://github.com/studychen/SeeNewsV2 假设对于 ...
- Android回到页面并刷新数据
通过对Android Activity的生命周期的了解,需要在后退页面重写onResume()的方法. 建立自己更新数据的函数,并在onCreate()方法中调用. @Override protect ...
- Android Viewpager PagerAdapter update data 刷新界面数据
最近做的项目涉及到ViewPager数据刷新,网上的资料挺多,但是和现在做的这个不太相同,所以并没有找到有效的. 折腾了大半天,整理一下思路: 问题1: 后台刷新数据次数过多后,界面出现卡顿现象,判断 ...
- Android RecyclerView与ListView比较
RecyclerView 概述 RecyclerView 集成自 ViewGroup .RecyclerView是Android-support-V7版本中新增的一个Widgets,官方对于它的介绍是 ...
- SwipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉刷新
下拉刷新和上拉刷新都用SwipeRefreshLayout 自带的进度条 布局 <?xml version="1.0" encoding="utf-8"? ...
- Android RecyclerView的基本使用
Android RecyclerView 在去年的Google I/O大会上就推出来了,以前经常使用的ListView 继承的是AbsListView,而RecyclerView则直接继承 ViewG ...
- Android RecyclerView网格布局
一个简单的网格布局activity_main.xml <?xml version="1.0" encoding="utf-8"?> <andr ...
- Android之SwipeRefreshLayout下拉刷新组件
SwipeRefreshLayout概述 SwipeRefrshLayout是Google官方更新的一个Widget,可以实现下拉刷新的效果.该控件集成自ViewGroup在support-v4兼容包 ...
随机推荐
- Docker 09 可视化
参考源 https://www.bilibili.com/video/BV1og4y1q7M4?spm_id_from=333.999.0.0 https://www.bilibili.com/vid ...
- 用RocketMQ这么久,才知道消息可以这样玩
在上一章节中,我们讲解了RocketMQ的基本介绍,作为MQ最重要的就是消息的使用了,今天我们就来带大家如何玩转MQ的消息. 消息中间件,英文Message Queue,简称MQ.它没有标准定义,一般 ...
- RabbitMQ 入门系列:3、基础含义:持久化、排它性、自动删除、强制性、路由键。
系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...
- 老梗新玩「GitHub 热点速览 v.22.34」
作者:HelloGitHub-小鱼干 不知道你是否和我有一样的烦恼,最近的流行梗当自己要用拿来造词时,就陷入了不知道咋"换壳"的尴尬地步.sao-gen-gen 大大减少了你老梗新 ...
- suse 11 sp3编译报错问题
suse安装,默认是不安装gcc的,今天安装gcc之后,编译suse11 sp3,报错如下: scripts/basic/fixdep.c:106:23: fatal error: sys/types ...
- html、css实现导航栏5种常用下拉效果
实现的效果:鼠标移入按钮时按钮中的内容就会出现,分别展示不同的出现效果.效果难点:不使用JavaScript,那这个效果的难点就是在于:hover伪类的掌控,以及考验对html的结构掌握. 1. ht ...
- 通过宏封装实现std::format编译期检查参数数量是否一致
背景 std::format在传参数量少于格式串所需参数数量时,会抛出异常.而在大部分的应用场景下,参数数量不一致提供编译报错更加合适,可以促进我们更早发现问题并进行改正. 最终效果 // 测试输出接 ...
- KingbaseES V8R6C5B041 sys_backup.sh单实例备份案例
数据库版本: test=# select version(); version ---------------------------------------------------------- ...
- Vim使用技巧(持续更新)
好记性不如烂笔头,在这里记录一些Vim使用技巧 vim配置 "拷贝同步到系统剪切板" set clipboard=unnamed "显示行号" set nu & ...
- 《Java基础——数组的定义与使用》
Java基础--数组的定义与使用 一. 一维数组: 格式一: 数组类型 数组变量[]=new 数据类型[长度]; //需要后续赋值,且后续赋值时只能为单个元素赋值. 或 数组类型 数组变量 ...