Android 基础技术——RecyclerView

笔者希望做一个系列,整理 Android 基础技术,本章是关于 RecyclerView

RecyclerView 对比 ListView 的优点
  • Adapter 面向的是 ViewHolder 不是 View, 可以省略 convertView.setTag 和 getTag 这些步骤
  • 可以设置布局管理器:竖向、横向、瀑布流方式
  • 可以设置 Item 的间隔样式
  • Recycleview去掉了一些api,比如setEmptyview,onItemClickListener等等,给到用户更多的自定义可能
  • Recycleview去掉了设置头部底部item的功能,专向通过viewholder的不同type实现
  • Recycleview实现了一些局部刷新,比如notifyitemchanged
  • Recycleview自带了一些布局变化的动画效果,也可以通过自定义ItemAnimator类实现自定义动画效果
  • Recycleview缓存机制更全面,增加两级缓存,还支持自定义缓存逻辑

RecyclerView 一共有几级缓存

mAttachedScrap(屏幕内),mCacheViews(屏幕外),mViewCacheExtension(自定义缓存),mRecyclerPool(缓存池)

  • mAttachedScrap(屏幕内),用于屏幕内itemview快速重用,不需要重新createView和bindView
  • mCacheViews(屏幕外),保存最近移出屏幕的ViewHolder,包含数据和 position 信息,复用时必须是相同位置的 ViewHolder 才能复用,应用场景在那些需要来回滑动的列表中,当往回滑动时,能直接复用ViewHolder数据,不需要重新bindView
  • mViewCacheExtension(自定义缓存),不直接使用,需要用户自定义实现,默认不实现。
  • mRecyclerPool(缓存池),当cacheView满了后或者adapter被更换,将cacheView中移出的ViewHolder放到Pool中,放之前会把ViewHolder数据清除掉,所以复用时需要重新bindView

RecyclerView 的缓存流程是怎样的
  • 保存缓存流程:
    • 插入或是删除itemView时,先把屏幕内的ViewHolder保存至AttachedScrap中
    • 滑动屏幕的时候,先消失的itemview会保存到CacheView,CacheView大小默认是2,超过数量的话按照先入先出原则,移出头部的itemview保存到RecyclerPool缓存池(如果有自定义缓存就会保存到自定义缓存里),RecyclerPool缓存池会按照itemview的itemtype进行保存,每个itemType缓存个数为5个,超过就会被回收
  • 获取缓存流程:
    • AttachedScrap中获取,通过pos匹配holder——>获取失败,从CacheView中获取,也是通过pos获取holder缓存 ——>获取失败,从自定义缓存中获取缓存——>获取失败,从mRecyclerPool中获取 ——>获取失败,重新创建viewholder——createViewHolder并bindview。

说下做过的RecyclerView 性能优化
  • bindViewHolder方法是在UI线程进行的,此方法不能耗时操作,不然将会影响滑动流畅性。比如进行日期的格式化。
  • 对于新增或删除的时候,可以使用diffutil进行局部刷新,少用全局刷新
  • 对于itemVIew进行布局优化,比如少嵌套等。
  • 加大RecyclerView缓存,比如cacheview大小默认为2,可以设置大点,用空间来换取时间,提高流畅度
  • 如果高度固定,可以设置setHasFixedSize(true)来避免requestLayout浪费资源,否则每次更新数据都会重新测量高度。
  • 如果多个RecycledView 的 Adapter 是一样的,比如嵌套的 RecyclerView 中存在一样的 Adapter,可以通过设置 RecyclerView.setRecycledViewPool(pool) 来共用一个 RecycledViewPool。这样就减少了创建VIewholder的开销。
  • 在RecyclerView的元素比较高,一屏只能显示一个元素的时候,第一次滑动到第二个元素会卡顿。这种情况就可以通过设置额外的缓存空间,重写getExtraLayoutSpace方法即可。
  • 设置RecyclerView.addOnScrollListener() 来在滑动过程中停止加载的操作。
  • 减少对象的创建,比如设置监听事件,可以全局创建一个,所有view公用一个listener,并且放到CreateView里面去创建监听,因为CreateView调用要少于bindview。这样就减少了对象创建所造成的消耗
  • 用notifyDataSetChange时,适配器不知道整个数据集中的那些内容以及存在,再重新匹配ViewHolder时会花生闪烁。设置adapter.setHasStableIds(true),并重写getItemId()来给每个Item一个唯一的ID,也就是唯一标识,就使itemview的焦点固定,解决了闪烁问题

RecyclerView 为什么可以做到局部刷新

RecyclerView的局部刷新就是依赖Scrap的临时缓存,当我们通过notifyItemRemoved(),notifyItemChanged()通知item发生变化的时候,通过mAttachedScrap缓存没有发生变化的ViewHolder,其他的则由mChangedScrap缓存,添加itemView的时候快速从里面取出,完成局部刷新。

注意,如果我们使用notifyDataSetChanged()来通知RecyclerView刷新,屏幕上的itemView被标记为FLAG_INVALID并且未被移除,所以不会使用Scrap缓存,而是直接扔到CacheView或者RecycledViewPool池中,回来的时候重新走一次绑定数据

注意:itemE并没有出现在屏幕中,它不属于Scrap管辖的范围,Scrap只会缓存在屏幕中已经加载出来的itemView的holder

RecycerView 如何缓存不同的itemType的ViewHolder

    public static class RecycledViewPool {
        private static final int DEFAULT_MAX_SCRAP = 5;
        static class ScrapData {
            final ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
            int mMaxScrap = DEFAULT_MAX_SCRAP;
        }
        SparseArray<ScrapData> mScrap = new SparseArray<>();
    }

可以看出,RecycledViewPool中定义了SparseArray<ScrapData> mScrap,它是一个根据不同itemType来保存静态类ScrapData对象的SparseArray,ScrapData中包含了ArrayList<ViewHolder> mScrapHeap ,mScrapHeap是保存该itemType类型下ViewHolder的ArrayList。

缓存池定义了默认的缓存大小DEFAULT_MAX_SCRAP = 5,这个数量不是说整个缓存池只能缓存这多个ViewHolder,而是不同itemType的ViewHolder的list的缓存数量,即mScrap的数量,说明最多只有5组不同类型的mScrapHeap。mMaxScrap = DEFAULT_MAX_SCRAP说明每种不同类型的ViewHolder默认保存5个,当然mMaxScrap的值是可以设置的。这样RecycledViewPool就把不同ViewType的ViewHolder按类型分类缓存起来。

简述RecyclerView 的回收原理

同时也是能做到局部刷新的原理

在RecyclerView重新布局onLayoutChildren()或者填充布局fill()的时候,会先把必要的item与屏幕分离或者移除,并做好标记,保存到list中,在重新布局时,再将ViewHolde拿出来重新一个个放到新的位置上去。

(1)如果是RecyclerView不滚动情况下缓存(比如删除item),重新布局时,把屏幕上的ViewHolder与屏幕分离下来,存放到Scrap中,即发生改变的ViewHolder缓存到mChangedScrap中,不发生改变的ViewHolder存放到mAttachedScrap中;剩下ViewHolder的会按照mCachedViews>RecycledViewPool的优先级缓存到mCachedViews或者RecycledViewPool中。

(2)如果是RecyclerVIew滚动情况下缓存(比如滑动列表),在滑动时填充布局,先移除滑出屏幕的item,第一级缓存mCachedViews优先缓存这些ViewHolder,但是mCachedViews最大容量为2,当mCachedViews满了以后,会利用先进先出原则,把旧的ViewHolder存放到RecycledViewPool中后移除掉,腾出空间,再将新的ViewHolder添加到mCachedViews中,最后剩下的ViewHolder都会缓存到终极回收池RecycledViewPool中,它是根据itemType来缓存不同类型的ArrayList<ViewHolder>,最大容量为5。

简述 RecyclerView 的复用原理

RecyclerView 有5个缓存池子mChangedScrap、mAttachedScrap、mCachedViews、mViewCacheExtension、mRecyclerPool,除了mViewCacheExtension是系统提供给开发者拓展的没有用到之外,还有四个池子是参与到复用流程中的。

当RecyclerView要拿一个复用的ViewHolder时,如果是预加载,则会先去mChangedScrap中精准查找(分别根据position和id)对应的ViewHolder,如果有就返回,如果没有就再去mAttachedScrap和mCachedViews中精确查找(先position后id)是不是原来的ViewHolder,如果是说明ViewHolder是刚刚被移除的,如果不是,则最终去mRecyclerPool找,如果itemType类型匹配对应的ViewHolder,那么返回实例,让它重新绑定数据,如果mRecyclerPool也没有返回ViewHolder才会调用createViewHolder()重新去创建一个。

这里需要注意:在mChangedScrap、mAttachedScrap、mCachedViews中拿到的ViewHolder都是精准匹配,但是mChangedScrap的是发生了变化的,需要调用onBindViewHolder()重新绑定数据,mAttachedScrap和mCachedViews没有发生变化,是直接使用的,不需要重新绑定数据,而mRecyclerPool中的ViewHolder的内容信息已经被抹除,需要重新绑定数据。所以在RecyclerView来回滚动时,mCachedViews缓存池的使用效率最高。

总的来说:RecyclerView着重在两个场景缓存和回收的优化,一是:在数据更新时,使用Scrap进行局部更新,尽可能复用原来viewHolder,减少绑定数据的工作;二是:在滑动的时候,重复利用原来的ViewHolder,尽可能减少重复创建ViewHolder和绑定数据的工作。最终思想就是,能不创建就不创建,能不重新绑定就不重新绑定,尽可能减少重复不必要的工作。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RUST笔记:candle使用基础

candle介绍 candle是huggingface开源的Rust的极简 ML 框架。 candle-矩阵乘法示例 cargo new myapp cd myapp cargo add --git https://github.com/huggingface/candle.git candle-core cargo build # 测试&#xff0c;或执行 cargo ckeckmain.rs use candle_core::{Device…

惊了!用vue开发官网,以前我觉得胡闹,现在觉得未尝不可。

以前&#xff0c;有人做好官网UI&#xff08;展示性&#xff0c;没啥功能&#xff09;&#xff0c;找我开发前端&#xff0c;说要vue来做&#xff0c;我都劝了。 基于以下四个原因&#xff1a; 1、官网毕竟还是考虑seo的&#xff0c;流量多少算多少&#xff0c;总比没有强&am…

Doris 与 Clickhouse 对比(一)

1. 常用引擎 ☕️ Doris 表数据模型 duplicate key &#x1f3ac; 场景&#xff1a;适用于数据无需提前聚合的分析业务。 ⚠️ 注意点&#xff1a;只指定排序列&#xff0c;相同的行并不会合并。 unique key &#x1f3ac; 场景&#xff1a;适用于有更新需求的业务。 ⚠…

Flink 集成 Debezium Confluent Avro ( format=debezium-avro-confluent )

博主历时三年精心创作的《大数据平台架构与原型实现:数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,京东购书链接:https://item.jd.com/12677623.html,扫描左侧二维…

数据结构——链式二叉树(2)

目录 &#x1f341;一、二叉树的销毁 &#x1f341;二、在二叉树中查找某个数&#xff0c;并返回该结点 &#x1f341;三、LeetCode——检查两棵二叉树是否相等 &#x1f315;&#xff08;一&#xff09;、题目链接&#xff1a;100. 相同的树 - 力扣&#xff08;LeetCode&a…

私有化部署ASR的方案,优缺点

私有化部署自动语音识别&#xff08;ASR&#xff09;系统的方案具有一些优点和缺点&#xff0c;下面苏州磐石云提出一些常见的优缺点&#xff1a; 优点&#xff1a; 数据隐私和安全性&#xff1a;私有化部署ASR系统可以确保数据在本地环境中进行处理和存储&#xff0c;更好地保…

《动手学深度学习(PyTorch版)》笔记4.5

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过。…

Notepad在文件中查找多行相同内容的文字

Notepad在文件中查找多行相同的内容 查找&#xff1a;打开 Notepad软件&#xff0c; Ctrl F 查找 。输入关键词&#xff0c; 点击【在当前文件中查找】。 复制&#xff1a;直接在下方的【搜索结果】复制。 Notepad提取含有特定字符串的行 详情见&#xff1a; https://blog…

[HTML]Web前端开发技术18(HTML5、CSS3、JavaScript )HTML5 基础与CSS3 应用——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

IndexedDB

Web SQL Database | Can I use... Support tables for HTML5, CSS3, etc IndexedDB | Can I use... Support tables for HTML5, CSS3, etc 为什么websql被废弃&#xff1f;_笔记大全_设计学院 WebSQL有兼容、性能、安全问题&#xff0c;要考虑使用IndexedDB替代。 一文看懂 In…

上位机图像处理和嵌入式模块部署(极致成本下的图像处理)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 目前&#xff0c;大家都习惯了特定的图像处理方式&#xff0c;要么是windows上位机来处理&#xff0c;要么是arm soc来进行处理&#xff0c;要么是…

远程git开发

两种本地与远程仓库同步 """ 1&#xff09;你作为项目仓库初始化人员&#xff1a;线上要创建空仓库 > 本地初始化好仓库 > 建立remote链接(remote add) > 提交本地仓库到远程(push)2&#xff09;你作为项目后期开发人员&#xff1a;远程项目仓库已经创…

快速恢复区域 - 空间管理警告和警报(文档 ID 305812.1)

快速恢复区域 - 空间管理警告和警报&#xff08;文档 ID 305812.1&#xff09;

Stable Diffusion插件Recolor实现黑白照片上色

今天跟大家分享一个使用Recolor插件通过SD实现老旧照片轻松变彩色&#xff0c;Recolor翻译过来的含义就是重上色&#xff0c;该模型可以保持图片的构图&#xff0c;它只会负责上色&#xff0c;图片不会发生任何变化。 一&#xff1a;插件下载地址 https://github.com/pkuliyi…

pinctrl子系统与gpio子系统实验-测试Led驱动框架代码

一. 简介 上一篇文章学习编写了 led驱动框架代码&#xff0c;并正常编译通过。文章地址如下&#xff1a; pinctrl子系统与gpio子系统实验-Led驱动框架代码实现-CSDN博客 本文对上一篇文章编写的驱动框架代码进行测试。测试方法与之前的驱动模块的测试方法一样。 二. 测试Le…

快速上手!使用Docker和Nginx部署Web服务的完美指南

前言 Docker是一种容器化技术&#xff0c;它可以将应用程序及其依赖项打包到一个独立的、可移植的容器中。这意味着开发人员可以在任何环境中轻松部署和运行他们的应用程序&#xff0c;而无需担心环境差异和依赖问题。而Nginx则是一款高性能的Web服务器和反向代理服务器&#x…

Chapter 8 - 1. Congestion Management in TCP Storage Networks

This chapter covers the following topics. 本章包括以下主题。 Understanding congestion in TCP storage networks. Detecting congestion in TCP storage networks. Traffic patterns with iSCSI and NVMe/TCP and correlation with network congestion. Preventing co…

Javaweb之SpringBootWeb案例之阿里云OSS服务集成的详细解析

2.3.3 集成 阿里云oss对象存储服务的准备工作以及入门程序我们都已经完成了&#xff0c;接下来我们就需要在案例当中集成oss对象存储服务&#xff0c;来存储和管理案例中上传的图片。 在新增员工的时候&#xff0c;上传员工的图像&#xff0c;而之所以需要上传员工的图像&…

C++版QT:分割窗口

目录 mainwindow.h mainwindow.cpp main.cpp Qt的分割窗口功能允许用户将一个窗口分割成多个区域&#xff0c;每个区域可以独立地显示不同的内容。这种功能在许多应用程序中非常有用&#xff0c;例如编辑器、浏览器和IDE等。 理解Qt的分割窗口&#xff0c;需要从以下几个方面…

SQL注入流程与常用语句

FLAG&#xff1a;别来我梦里了&#xff0c;我已负担不起醒来的失落 专研方向: Mysql&#xff0c;sql注入 每日emo&#xff1a;好久不见&#xff0c;寒暄几句&#xff0c;缺耗尽了半生的勇气 欢迎各位与我这个菜鸟交流学习 SQL注入流程与常用语句 1、判断注入类型&#xff0c;数…