Android RecyclerView使用ListAdapter高效刷新数据的操作方法
作者:Stars-one 发布时间:2023-06-24 22:22:09
我们都知道,当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技术)
来源:https://www.cnblogs.com/stars-one/p/16818620.html


猜你喜欢
- 前言我们在 页面切换转场动画,英雄救场更有趣!介绍了 Hero 动画效果,使用 Hero 用于转场能够提供非常不错的体验。既然称之
- 前言最近看插件库上少有的取色器大都是圆形的或者奇奇怪的的亚子,所以今天做两个矩形的颜色取色器提示:以下是本篇文章正文内容,下面案例可供参考一
- 在spring中有很多以XXXAware命名的接口,很多人也不清楚这些接口都是做什么用的,这篇文章将描述常用的一些接口。一,Applicat
- 本文的目的是要实现左右滑动的指引效果。那么什么是指引效果呢?现在的应用为了有更好的用户体验,一般会在应用开始显示一些指引帮助页面,使用户能更
- BitArray的基础可以看菜鸟编程BitArray 类管理一个紧凑型的位值数组,它使用布尔值来表示,其中 true 表示位是开启的(1),
- 最近“全网域(Web Scale)”一词被炒得火热,人们也正在通过扩展他们的应用程序架构来使他们的系统变得更加“全网域”。但是究竟什么是全网
- 开发环境win10Android Studio效果用于多级菜单展示,或选择。如 每个省,市,县;如 树木的病虫害;关键代码 @overrid
- 一、目的本篇文章的目的是记录本人使用flutter加载与调用第三方aar包。二、背景本人go后端,业余时间喜欢玩玩flutter。一直有一个
- 一、SpringCache介绍Spring Cache 是一个优秀的缓存组件。自Spring 3.1起,提供了类似于@Transaction
- 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。库分静态库和动态库两种。 一、静态库和动态库的区别1. 静态函数库这类库的
- 本文实例讲述了C#中HttpWebRequest的用法。分享给大家供大家参考。具体如下:HttpWebRequest类主要利用HTTP 协议
- 合成聚合复用原则合成复用原则又称为组合/聚合复用原则(Composition/Aggregate Reuse Principle, CARP
- 本文实例为大家分享了Unity实现场景漫游相机的具体代码,供大家参考,具体内容如下前言拿到场景后总喜欢在场景里面玩一段时间,那这个脚本就是你
- android中提供了4中动画: AlphaAnimation 透明度动画效果 ScaleAnimation 缩放动画效果 Translat
- 前言我们在学习Windows应用程序开发中,经常会用到消息对话框给用户或者管理员一些的消息提示,它们都是基于对MessageBox类的消息对
- 需求基于MTK8163 8.1平台定制导航栏部分,在左边增加音量减,右边增加音量加思路需求开始做之前,一定要研读SystemUI Navig
- 简介官方API文档Scaffold的of方法说明有说明调用Scaffold.of方法是在Scallfold的子组件的Build方法中,也就是
- 如图所示的效果相信大家都不陌生,我们可以使用很多种方法去实现此效果,这里自己采用CountDownTimer定时器简单封装下此效果,方便我们
- 前言上一篇我们认识了Kotlin编程语言,也搭建好开发环境。本篇就进入Kotlin的基础语法介绍,与其他编程语言一样,Kotlin也有自己的
- 1、前言当提及如何终止一个线程时,部分读者通常立马想到的方法肯定是stop(),但是stop()方法并不被推荐使用(很多规范中是禁止使用的)