当前位置:网站首页>Efficient use of RecyclerView Section 2
Efficient use of RecyclerView Section 2
2022-07-31 14:57:00 【[email protected]】
Lists are used the most in development,But performance is also probably the most overlooked part,在做性能优化时,We all know that when writing layouts, try to use Constraint Layout as much as possible,减少布局的嵌套层次,Reduce redundant backgrounds to improve layout parsing rendering speed,But that's just one point of optimization.Next, refer to the official oneAPICombined with the actual scene to further optimize the list-related.
一,DiffUtilDifferentiated refresh
相较于ListView,RecyclerViewLocal refresh is supported,Greatly improved performance when refreshing,但平时开发中,Most people do it for simplicity or being lazy,直接调用了RecyclerView的全局刷新,After all, you only need to write one line of code,Nothing will go wrong either,But when doing performance optimization,如果想更近一步,我们可以结合DiffUtilDo a differential refresh.
如下:
1,创建xml布局
1)Activity布局
<?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.appcompat.widget.AppCompatButton app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintHorizontal_weight="1" app:layout_constraintRight_toLeftOf="@+id/btn_loadMore" android:id="@+id/btn_refresh" android:text="refresh" android:gravity="center" android:layout_width="0dp" android:layout_height="wrap_content"/>
<androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_study" android:layout_width="match_parent" app:layout_constraintTop_toBottomOf="@+id/btn_refresh" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" android:orientation="vertical" tools:listitem="@layout/item_study" app:layout_constraintBottom_toBottomOf="parent" android:layout_height="0dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
2) item布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="16dp" xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.appcompat.widget.AppCompatImageView android:id="@+id/iv_icon" android:layout_width="48dp" app:layout_constraintLeft_toLeftOf="parent" android:src="@mipmap/ic_launcher" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_height="48dp"/>
<TextView app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toRightOf="@+id/iv_icon" android:layout_width="wrap_content" android:id="@+id/tv_title" android:gravity="center" android:text="Study" android:textSize="22sp" android:layout_marginLeft="16dp" app:layout_constraintVertical_chainStyle="packed" app:layout_constraintBottom_toTopOf="@+id/tv_second" android:textColor="@android:color/black" android:layout_height="wrap_content"/>
<TextView android:id="@+id/tv_subtitle" android:layout_width="wrap_content" app:layout_constraintLeft_toRightOf="@+id/iv_icon" app:layout_constraintTop_toBottomOf="@+id/tv_study" android:textSize="16sp" android:layout_marginLeft="16dp" app:layout_constraintVertical_chainStyle="packed" android:text="zhansan" android:textColor="@color/cardview_dark_background" app:layout_constraintBottom_toBottomOf="parent" android:layout_height="wrap_content"/>
<TextView android:id="@+id/tv_gender" android:layout_width="wrap_content" android:textSize="18sp" android:text="男" android:textColor="@color/material_on_surface_emphasis_high_type" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" android:textStyle="bold" app:layout_constraintBottom_toBottomOf="parent" android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
2,继承ListAdapter
package com.example.recyclerviewstudy.two
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SortedList
import com.example.recyclerviewstudy.R
import com.example.recyclerviewstudy.StudentInfo
class StudentAdapter:ListAdapter<StudentInfo, StudentAdapter.ViewHolder>(StudentDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_study,parent,false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
class ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
val tv_name: TextView = itemView.findViewById(R.id.tv_title)
val tv_age: TextView = itemView.findViewById(R.id.tv_subtitle)
val tv_gender:TextView = itemView.findViewById(R.id.tv_gender)
fun bind(entity:StudentInfo){
entity.apply {
tv_name.text = name
tv_age.text = "$age"
tv_gender.text = gender
}
}
}
}
//核心函数
class StudentDiffCallback:DiffUtil.ItemCallback<StudentInfo>(){
override fun areItemsTheSame(oldItem: StudentInfo, newItem: StudentInfo): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: StudentInfo, newItem: StudentInfo): Boolean {
return oldItem == newItem
}
}
Adapter中核心就两点:
1)继承ListAdapter
2)实现DiffUtil.ItemCallback,判断两个对象是否相同
3,Activity中初始化RecyclerView及Adapter
//学生数据列表
private val studentEntities = ArrayList<StudentInfo>()
//适配器
private val studentAdapter by lazy {
StudentAdapter()
}
初始化Adapter
val rv_student = findViewById<RecyclerView>(R.id.rv_student)
rv_student.adapter = studentAdapter
更新数据时
studentAdapter.submitList(studentEntities)
When the request interface is successful,直接调用submitList进行数据更新,Give it a refreshDiffUtil内部自行处理.
There are also certain limitations in using scenarios in this way,Suitable for list fixed,If you want to support the pull-down refresh type,需要基于DiffUtil.Callback进行实现
例如:
/**
* getOldListSize():旧数据集的长度.
getNewListSize():新数据集的长度
areItemsTheSame():判断是否是同一个Item.
areContentsTheSame():If it is a passItem,此方法用于判断是否同一个 Item 的内容也相同
*/
private fun diffCallBack(oldDataSource:ArrayList<StudentInfo>,
newDataSource:ArrayList<StudentInfo>) =
object :DiffUtil.Callback(){
override fun getOldListSize() = oldDataSource.size
override fun getNewListSize() = newDataSource.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldDataSource[oldItemPosition].name == newDataSource[newItemPosition].name
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
if (oldDataSource[oldItemPosition].name != newDataSource[newItemPosition].name||
oldDataSource[oldItemPosition].age == newDataSource[newItemPosition].age){
return false
}
return true
}
override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
return super.getChangePayload(oldItemPosition, newItemPosition)
}
}
DiffUtilThe difference algorithm is used internally,Differentiated objects are calculated,然后调用RecyclerView的insert,deleteWait for the function to perform a local refresh,Improve refresh efficiency.
二,AsyncListDiffer Asynchronous differential refresh
DiffUtilCan solve the local refresh problem,但也存在缺陷,当数据量大时,会卡主线程,Its data comparison is carried out on the main thread,所以当数据量大时,则推荐使用AsyncListDifferPerform an asynchronous differential comparison refresh,提升性能.
相对于DiffUtilThe difference in usage is mainly reflected in Adapter上,详见如下代码 :
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.example.recyclerviewstudy.R
import com.example.recyclerviewstudy.StudentInfo
class AsyncStudentAdapter:RecyclerView.Adapter<AsyncStudentAdapter.ViewHolder>() {
//创建AsyncListDiffer对象,传入DiffUtil.ItemCallback
private val mDiffer = AsyncListDiffer(this,StudentDiffCallback())
fun submit(list:List<StudentInfo>){
mDiffer.submitList(list)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_study, parent, false)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(mDiffer.currentList[position])
}
override fun getItemCount() = mDiffer.currentList.size
class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView){
val tv_name: TextView = itemView.findViewById(R.id.tv_title)
val tv_age: TextView = itemView.findViewById(R.id.tv_subtitle)
val tv_gender: TextView = itemView.findViewById(R.id.tv_gender)
fun bind(entity: StudentInfo){
entity.apply {
tv_name.text = name
tv_age.text = "$age"
tv_gender.text = gender
}
}
}
class StudentDiffCallback: DiffUtil.ItemCallback<StudentInfo>(){
override fun areItemsTheSame(oldItem: StudentInfo, newItem: StudentInfo): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: StudentInfo, newItem: StudentInfo): Boolean {
return oldItem == newItem
}
}
}
其核心步骤如下:
1)实现 StudentDiffCallbackIn it, define the differentiation of the object entity.
2)创建AsyncListDiffer对象,传入DiffUtil.ItemCallback对象
3)定义一个submit函数,For refreshing external data
在使用时,直接调用adapter的submitRefresh the data list.
三,SortedListQuickly sort the list
In some cases when we need to sort the data list,很多人想到的是,Iterate through the comparison and sort one by one,效率低下,When encountering a large amount of data,long time condition,If it is not handled properly, there will be many problems,如果使用SortedListThis greatly improves the sorting efficiency,It also makes the code logic more clear.
The concrete example is also based on the starting layout problem,核心代码主要在Adapter中,如下:
class TeacherAdapter:RecyclerView.Adapter<TeacherAdapter.ViewHolder>() {
//核心点
private val sortedList by lazy {
SortedList(TeacherInfo::class.java,sortListCallback(this))
}
fun submit(list:List<TeacherInfo>){
sortedList.beginBatchedUpdates()
sortedList.addAll(list)
sortedList.endBatchedUpdates()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_study,parent,false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(sortedList.get(position))
}
override fun getItemCount() = sortedList.size()
class ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
val tv_name: TextView = itemView.findViewById(R.id.tv_title)
val tv_age: TextView = itemView.findViewById(R.id.tv_subtitle)
val tv_gender: TextView = itemView.findViewById(R.id.tv_gender)
fun bind(entity: TeacherInfo){
entity.apply {
tv_name.text = name
tv_age.text = "$age"
tv_gender.text = gender
}
}
}
//继承SortedListAdapterCallback定义排序规则
class sortListCallback(adapter:RecyclerView.Adapter<*>):
SortedListAdapterCallback<TeacherInfo>(adapter){
//用来排序
override fun compare(o1: TeacherInfo, o2: TeacherInfo): Int {
return o1.id.compareTo(o2.id)
}
override fun areContentsTheSame(oldItem: TeacherInfo, newItem: TeacherInfo): Boolean {
return oldItem.hashCode() == newItem.hashCode()
}
override fun areItemsTheSame(item1: TeacherInfo, item2: TeacherInfo): Boolean {
return item1.id == item2.id
}
}
}
如上便是SortedList的核心代码,在使用时,直接submitRefresh the data,Of course, it also provides a lot of inserting a single data or deleting a single dataapi,更多的用法参考官方API文档
四,ConcatAdapter连接多个Adapter
When a page consists of multiple different categories,可以使用ConcatAdapter进行Adapter拼接,但其也存在一定的局限性,Because the same one is usedRecyclerView,So its list layout direction must be consistent,The usage is also very simple and straightforward to createConcatAdapter对象,传入相应的Adapter即可
val rv_student = findViewById<RecyclerView>(R.id.rv_student)
val concatAdapter = ConcatAdapter(studentAdapter, asyncStudentAdapter)
rv_student.adapter = concatAdapter
关键RecyclerView的使用,This concludes the second chapter.The example security in the text is for reference only,It can be expanded according to actual needs during development,Please advise if there are mistakes or more efficient usage.
版权声明
本文为[[email protected]]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/212/202207311451011572.html
边栏推荐
- Uniapp WeChat small application reference standard components
- LeetCode二叉树系列——110.平衡二叉树
- The paper manual becomes 3D animation in seconds, the latest research of Wu Jiajun of Stanford University, selected for ECCV 2022
- Small test knife: Go reflection helped me convert Excel to Struct
- [QNX Hypervisor 2.2 User Manual]9.14 safety
- c语言hello world代码(代码编程入门)
- 格林美瑞交所IPO:募资3.8亿美元 更多中国企业将赴欧洲上市
- OAuth2:使用JWT令牌
- 基于极限学习机(ELM)进行多变量用电量预测(Matlab代码实现)
- Gorm—Go语言数据库框架
猜你喜欢
Recommendation System - Recall Phase - 2013: DSSM (Twin Towers Model) [Embedding (Semantic Vector) Recall] [Microsoft]
MySQL [aggregate function]
The meaning of node_exporter performance monitoring information collection in Prometheus
Node实现数据加密
英文语法-时与态
格林美瑞交所IPO:募资3.8亿美元 更多中国企业将赴欧洲上市
为什么要分库分表?
OpenCV测量物体的尺寸技能 get~
Asynchronous processing business using CompletableFuture
Five dimensions to start MySQL optimization
随机推荐
UnityShader入门学习(二)——渲染流水线
Spark学习(3)-Spark环境搭建-Standalone
公告
The JVM a class loader
谷歌CTS测试(cta测试)
Use of el-tooltip
NPM Taobao mirror (latest version) released a new version of npm mirror at 2021-11-21 16:53:52 [easy to understand]
Sentinel安装与部署
Redis与分布式:集群搭建
R语言ggplot2可视化:使用ggpubr包的ggmaplot函数可视化MA图(MA-plot)、font.legend参数和font.main参数设置标题和图例字体加粗
网线RJ45接口针脚[通俗易懂]
名创优品斥资6.95亿购买创始人叶国富所持办公楼股权
梅克尔工作室-第一次
Sentinel限流和异常处理
Getting started with UnityShader (3) - Unity's Shader
leetcode303场周赛复盘
LeetCode二叉树系列——222.完全二叉树的节点个数
2021 OWASP TOP 10 Vulnerability Guide
使用 Chainlink Keepers 实现智能合约函数的自动化执行
Redis与分布式:主从复制