当前位置:网站首页>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
边栏推荐
- redhat/openssl generates a self-signed ca certificate and uses it
- 看交互设计如何集成到Scrum敏捷流程中
- OAuth2:单点登陆客户端
- Sentinel流量控制
- R语言计算时间序列数据的移动平均值(滚动平均值、例如5日均线、10日均线等):使用zoo包中的rollmean函数计算k个周期移动平均值
- The use of thread pool two
- 华医网冲刺港股:5个月亏2976万 红杉与姚文彬是股东
- /etc/profile、/etc/bashrc、~/.bash_profile、~/.bashrc 文件的作用
- 梅克尔工作室-第一次
- 自适应控制——仿真实验三 用超稳定性理论设计模型参考自适应系统
猜你喜欢
随机推荐
How to clean up the lodash.memoize cache in the element-plus virtual table virtual-list component?
常用工具命令速查表
安装Xshell并使用其进行Ymodem协议的串口传输
蔚来杯2022牛客暑期多校训练营4
五个维度着手MySQL的优化
Redis与分布式:集群搭建
梅克尔工作室-第一次
Network cable RJ45 interface pins [easy to understand]
以后面试官问你 为啥不建议使用Select *,请你大声回答他!
小试牛刀:Go 反射帮我把 Excel 转成 Struct
Ubantu专题4:xshell、xftp连接接虚拟机以及设置xshell复制粘贴快捷键
I summed up the bad MySQL interview questions
Prometheus之node_exporter性能监控信息采集含义
架构实战营模块8消息队列表结构设计
微服务架构选型
公告
看交互设计如何集成到Scrum敏捷流程中
QGIS 加载WMS数据,重新投影
Introductory UnityShader learning (2) - the rendering pipeline
英文语法-时与态









