当前位置:网站首页>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
边栏推荐
- I summed up the bad MySQL interview questions
- Small test knife: Go reflection helped me convert Excel to Struct
- 三角恒等变换公式
- Groupid(artifact id)
- LeetCode二叉树系列——226.翻转二叉树
- 《微信小程序-进阶篇》Lin-ui组件库源码分析-Icon组件
- Ubantu专题4:xshell、xftp连接接虚拟机以及设置xshell复制粘贴快捷键
- 49. The copy constructor and overloaded 】
- 微信聊天记录中搜索红包
- SetoolKit User Guide
猜你喜欢

TCP详解

I summed up the bad MySQL interview questions

使用 PyTorch 检测眼部疾病

Architecture actual combat battalion module 8 message queue table structure design

OAuth2:资源服务器

The 232-layer 3D flash memory chip is here: the single-chip capacity is 2TB, and the transmission speed is increased by 50%
![Recommendation System - Recall Phase - 2013: DSSM (Twin Towers Model) [Embedding (Semantic Vector) Recall] [Microsoft]](/img/40/b567780ed2cf04f1f1336922816f86.png)
Recommendation System - Recall Phase - 2013: DSSM (Twin Towers Model) [Embedding (Semantic Vector) Recall] [Microsoft]

自适应控制——仿真实验二 用Narendra方案设计模型参考自适应系统

大健云仓冲刺美股:增营收反减利润 京东与DCM是股东

OpenShift 4 - 用 Operator 部署 Redis 集群
随机推荐
Web自动化实战——Selenium4(自动化测试环境的搭建)
Advanced Mathematics - Commonly Used Indefinite Integral Formulas
Redis与分布式:主从复制
网线RJ45接口针脚[通俗易懂]
R语言向前或者向后移动时间序列数据(自定义滞后或者超前的期数):使用dplyr包中的lag函数将时间序列数据向前移动一天(设置参数n为正值)
Getting started with UnityShader (1) - GPU and Shader
Small test knife: Go reflection helped me convert Excel to Struct
MySQL 23道经典面试吊打面试官
三角恒等变换公式
Groupid(artifact id)
【CUDA学习笔记】初识CUDA
R语言ggplot2可视化:使用ggpubr包的ggmaplot函数可视化MA图(MA-plot)、font.legend参数和font.main参数设置标题和图例字体加粗
OpenCV测量物体的尺寸技能 get~
Sentinel安装与部署
搭建私有的的Nuget包服务器教程
如何进行需求分析评审
格林美瑞交所IPO:募资3.8亿美元 更多中国企业将赴欧洲上市
[Pytorch] F.softmax() method description
Unity Shader入门精要学习——透明效果
763.划分字母区间——之打开新世界