• Android RecyclerView使用ListAdapter高效刷新数据


    本文为作者原创,允许转载,不过请在文章开头明显处注明链接和出处!!! 谢谢配合~
    作者:stars-one
    链接:https://www.cnblogs.com/stars-one/p/16818620.html

    本篇大约有3658个字,阅读预计需要4.57分钟


    原文: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, val newList: ArrayList) :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(diffCallback) {
    
        companion object {
            val diffCallback = object : DiffUtil.ItemCallback() {
                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第一个泛型即为你的数据实体类,第二个参数为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)
    

    效果:

    参考

  • 相关阅读:
    STM32 寄存器操作 systick 滴答定时器 与中断
    【五、接口自动化测试】5分钟掌握python + requests接口测试
    Java笔记--注解
    Nginx - 反向代理与负载均衡
    5G与无人驾驶:引领未来交通的新潮流
    B树、B+树、红黑树的定义、之间的区别、优缺点、数据结构、应用等
    PostgreSQL的学习心得和知识总结(一百一十二)|语法级自上而下完美实现PostgreSQL数据库的 EXCHANGE PARTION 的实现方案
    Python爬虫实战-批量爬取豆瓣电影排行信息
    MR混合现实情景实训教学系统在临床医学课堂教学中的应用
    使用RANKX计算层级排名
  • 原文地址:https://www.cnblogs.com/stars-one/p/16818620.html