DiffUtil + RecyclerView 在 Kotlin中的使用

很惭愧, 做了多年的Android开发还没有使用过DiffUtil这样解放双手的工具。

文章目录

  • 1 DiffUtil 用来解决什么问题?
  • 2 DiffUtil 是什么?
  • 3 DiffUtil的使用
  • 4 参考文章

1 DiffUtil 用来解决什么问题?

先举几个实际开发中的例子帮助我们感受下:

  • 加载内容流时,第一次加载了ABC,第二次加载了BCD,如何让用户能看到不重复的内容?
  • 网络数据和本地数据不一致, 如何能够找出不一致的内容?

我们可以采用最笨的方法, 自己比较两个集合的差异,但是效率较低,每个开发者都要重复做这样的事情, 是谷歌不愿意看到的。

2 DiffUtil 是什么?

DiffUtil is a utility class that calculates the difference between two lists and outputs a list of update operations that converts the first list into the second one.

It can be used to calculate updates for a RecyclerView Adapter. See ListAdapter and AsyncListDiffer which can simplify the use of DiffUtil on a background thread.

DiffUtil uses Eugene W. Myers’s difference algorithm to calculate the minimal number of updates to convert one list into another. Myers’s algorithm does not handle items that are moved so DiffUtil runs a second pass on the result to detect items that were moved.

DiffUtil 是一个实用程序类,它计算两个列表之间的差异并输出将第一个列表转换为第二个列表的更新操作列表。

它可用于计算 RecyclerView 适配器的更新。请参阅 ListAdapter 和 AsyncListDiffer,它们可以简化后台线程上 DiffUtil 的使用。

DiffUtil 使用 Eugene W. Myers 的差分算法来计算将一个列表转换为另一列表所需的最小更新次数。 Myers 的算法不处理已移动的项目,因此 DiffUtil 对结果运行第二遍以检测已移动的项目。

3 DiffUtil的使用

item_song_info.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:padding="16dp"><!-- Title TextView --><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Title"android:textSize="20sp"android:textStyle="bold" /><!-- Spacer View to add space between title and subtitle --><Viewandroid:layout_width="8dp"android:layout_height="match_parent" /><!-- Subtitle TextView --><TextViewandroid:id="@+id/tv_sub_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Subtitle"android:textSize="16sp" />
</LinearLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>

MusicBean.kt

data class MusicBean(var type: Int, var title: String, val subTitle: String)

MainActivity.kt

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val recyclerView: RecyclerView = findViewById(R.id.recyclerView)recyclerView.layoutManager = LinearLayoutManager(this)val adapter = MyAdapter()recyclerView.adapter = adapteradapter.data = getSampleDataA()Handler(Looper.getMainLooper()).postDelayed({adapter.data = getSampleDataB()}, 2000)}// 用于生成初始数据private fun getSampleDataA(): List<MusicBean> {val data = mutableListOf<MusicBean>()for (i in 1..10) {MusicBean(type = i, title = "ItemA $i", subTitle = "subTitle $i").let {data.add(it)}}return data}// 用于生成变化后的数据private fun getSampleDataB(): List<MusicBean> {val data = mutableListOf<MusicBean>()for (i in 1..10) {val tag = if (i <= 5) {"B"} else "A"MusicBean(type = i, title = "Item$tag $i", subTitle = "subTitle $i").let {data.add(it)}}return data}class MyAdapter : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {var data: List<MusicBean> = emptyList()set(value) {// 如果比较的集合较多(比如超过1000个), 建议使用子线程去比较val diffResult = DiffUtil.calculateDiff(MyDiffCallback(field, value))// 旧值赋新值field = value// 这里一定要保证在主线程调用diffResult.dispatchUpdatesTo(this)}class MyDiffCallback(private val oldList: List<MusicBean>, private val newList: List<MusicBean>) : DiffUtil.Callback() {override fun getOldListSize(): Int = oldList.sizeoverride fun getNewListSize(): Int = newList.sizeoverride fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {// 把这里想成是比较holder的类型, 比如纯文本的holder和纯图片的holder的type肯定不同return oldList[oldItemPosition].type == newList[newItemPosition].type}override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {// 把这里想成是同一种holder的比较,比如都是纯文本holder,但是title不一致return oldList[oldItemPosition].title == newList[newItemPosition].title}}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {val view =LayoutInflater.from(parent.context).inflate(R.layout.item_song_info, parent, false)return MyViewHolder(view)}override fun onBindViewHolder(holder: MyViewHolder, position: Int) {val item = data[position]holder.bind(item)}override fun getItemCount(): Int {return data.size}class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {fun bind(item: MusicBean) {val tvTitle: TextView = itemView.findViewById(R.id.tv_title)val tvSubTitle: TextView = itemView.findViewById(R.id.tv_sub_title)tvTitle.text = item.titletvSubTitle.text = item.subTitle}}}
}

在这里插入图片描述

4 参考文章

DiffUtil 官方介绍
将 DiffUtil 和数据绑定与 RecyclerView 结合使用
DiffUtil和它的差量算法
DiffUtils 遇到 Kotlin,榨干视图局部刷新的最后一滴性能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/285378.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hadoop3.x完全分布式模式下slaveDataNode节点未启动调整

目录 前言 一、问题重现 1、查询Hadoop版本 2、集群启动Hadoop 二、问题分析 三、Hadoop3.x的集群配置 1、停止Hadoop服务 2、配置workers 3、从节点检测 4、WebUI监控 总结 前言 在大数据的世界里&#xff0c;Hadoop绝对是一个值得学习的框架。关于Hadoop的知识&…

50ms时延工业相机

华睿工业相机A3504CG000 参数配置&#xff1a; 相机端到端理论时延&#xff1a;80ms 厂家同步信息&#xff0c;此款设备帧率上线23fps&#xff0c;单帧时延&#xff1a;43.48ms&#xff0c;按照一图缓存加上传输显示的话&#xff0c;厂家预估时延在&#xff1a;80ms 厂家还有…

亿某通电子文档安全管理系统任意文件上传漏洞 CNVD-2023-59471

1.漏洞概述 亿某通电子文档安全管理系统是一款电子文档安全防护软件,该系统利用驱动层透明加密技术,通过对电子文档的加密保护,防止内部员工泄密和外部人员非法窃取企业核心重要数据资产。亿赛通电子文档安全管理系统UploadFileFromClientServiceForClient接口处存在任意文件…

Java EE 网络之网络编程

文章目录 1. 什么是网络编程1.1 基础概念 2. Socket 套接字2.1 概念2.2 分类2.2.1TCP 和 UDP 的区别 2.3 UDP数据报套接字编程2.3.1 DatagramSocket2.3.2 DatagramPacket2.3.3 写一个简单的 UDP 的客户端程序2.3.3.1 编写服务器代码2.3.3.2 编写客户端代码 2.3.4 编写基于 echo…

C++11特性:可调用对象以及包装器function的使用

在C中存在“可调用对象”这么一个概念。准确来说&#xff0c;可调用对象有如下几种定义&#xff1a; 是一个函数指针&#xff1a; int print(int a, double b) {cout << a << b << endl;return 0; } // 定义函数指针 int (*func)(int, double) &print…

giee 添加公匙 流程记录

一、安装 百度网盘CSDN4文件夹下&#xff0c;或者官网下载&#xff1a;https://git-scm.com/downloads 二、生成密钥 1.右击打开git bash 2.$ ssh-keygen -t rsa -C “个人邮箱地址”&#xff0c;按3个回车&#xff0c;密码为空。 3.在C:\Users{windows用户名}.ssh目录下得到…

onvif协议笔记

一、简介 ONVIF官网 ONVIF协议网络摄像机&#xff08;IPC&#xff09;客户端程序开发&#xff08;1&#xff09;&#xff1a;专栏开篇 onvif协议开发 二、gSOAP gsoap官网 1、下载和编译 下载地址 #! /bin/sh # 指定源码目录(解压源码) GSOAP_SRCgsoap-2.8 PWDpwd echo &…

LiteClient工具箱:降低成本,减少监管风险

​​发表时间&#xff1a;2023年9月14日 BSV区块链协会的工程团队一直在为即将推出的LiteClient而努力工作&#xff0c;这是一套模块化的组件&#xff0c;可使简易支付验证&#xff08;SPV&#xff09;变得更加便利。 借助LiteClient工具箱&#xff0c;交易所可以通过区块头中…

网络空间搜索引擎- FOFA的使用技巧总结

简介 FOFA是一款网络空间测绘的搜索引擎&#xff0c;旨在帮助用户以搜索的方式查找公网上的互联网资产。 FOFA的查询方式类似于谷歌或百度&#xff0c;用户可以输入关键词来匹配包含该关键词的数据。不同的是&#xff0c;这些数据不仅包括像谷歌或百度一样的网页&#xff0c;还…

AWS RDS慢日志文件另存到ES并且每天发送邮件统计慢日志

1.背景&#xff1a;需要对aws rds慢日志文件归档到es&#xff0c;让开发能够随时查看。 2.需求&#xff1a;并且每天把最新的慢日志&#xff0c;过滤最慢的5条sql 发送给各个产品线的开发负责人。 3.准备&#xff1a; aws ak/sk &#xff0c;如果rds 在不同区域需要认证不同的…

七轴开源协作机械臂myArm视觉跟踪技术!

引言 ArUco标记是一种基于二维码的标记&#xff0c;可以被用于高效的场景识别和位置跟踪。这些标记的简单性和高效性使其成为机器视觉领域的理想选择&#xff0c;特别是在需要实时和高精度跟踪的场景中。结合机器学习和先进的图像处理技术&#xff0c;使用ArUco标记的机械臂系统…

「数据结构」二叉树1

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;C启航 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 文章目录 &#x1f349;树&#x1f349;二叉树&#x1f34c;特殊二叉树&#x1f34c;二叉树的性质&#x1f34c;存储结构 &#x1f349;…