当前位置: 首页 > news >正文

RecyclerView的缓存机制(面试常客)

在构建滚动列表时,我们常首选RecyclerView,出于它优秀的缓存复用机制。

核心机制

RecyclerView的缓存机制又称回收复用机制,RecyclerView构建列表视图分为以下三步:

 第一步的创建ViewHolder是RecyclerView构建视图时最耗时的操作,而RecyclerView正是因为做到了缓存复用,从而减少调用创建ViewHolder的次数。

当列表被创建时结构如下,每个ViewHolder中的A、B代表不同的View种类(ViewType):

当我们滚动第一个ViewHolder(此处简称p0)到屏幕以外时,它会被存入mCachedViews中:

此处被回收的p0依旧保存着之前的数据,各种内部状态没有被重置。

如果我们向上滚动,被缓存的p0会从mCachedViews缓存区中移回列表:

 

因此不需要重复CreateViewHolder和BindViewHolder,减少了耗时。

可见,缓存区是用来存储最近离开屏幕区的ViewHolder。 这些ViewHolder因为出于屏幕区的边界,更容易因为用户的滚动和抖动被重新显示,因此更需要被快速的加载到视图中。

缓存区存储ViewHolder的默认大小为2,开发者可根据实际需求更改大小。

当缓存区已满,而有新的ViewHolder被放入缓存区时,最先被置入缓存区的ViewHolder会被移到mRecyclerPool中:

进入mRecyclerPool的ViewHolder各种内部状态会被重置,如position会被置为-1,可理解为与之前的数据已解绑;图中的A和B表示不同的ViewType,每个能存储5个ViewHolder,这个大小也是可以被修改的。

分析完列表移出ViewHolder的过程,我们反过来看移入ViewHolder的:

假设此时有一个新的类型为B的ViewHolder(简称p7)要移入屏幕区。

首先查看缓存区中是否有可以复用的ViewHolder。这是因为被放入此处的ViewHolder是不需要重置数据的,因此优先考虑这里的ViewHolder,如果有相同的position,就会被取出复用。此处的逻辑和前面p0重新移入的逻辑相同;

图中的例子position=7,与缓存区中的两个ViewHolder的position都不相同,因此无法复用;接下来查看循环池中的ViewHolder。因为View类型为B的循环池中没有ViewHolder,所以依然无法复用;此时我们只能重新走Create和Bind的方法。

如果循环池中有相同类型的ViewHolder:

会从循环池中取出复用,因为被放入循环池中的ViewHolder都是被重置了的,虽然不用走Create方法,但是重新的Bind还是要有的。

是否可以只用一种ViewType?

对于不同的ViewType我们有不同的循环池,那我们是否可以只用一种ViewType,延长这一个循环池,提高回收复用率?

首先是可读性和可维护性会变差。因为不同的ViewType通常数据结构和视图样式方式不同,如果为了让一种ViewType都适配他们,代码肯定会变得很乱。

其次是不用懒加载,增加调用耗时;使用懒加载,无法避免视图切换耗时。首先因为ViewType的数据结构和视图样式等诸多内容不尽相同,如果一次全部加载内存开销必然很大,因此我们使用懒加载的方式最为合适,只有需要的时候才取出使用;

但因为我们把原本应该设计为不同的ViewType都塞进了一个ViewType,导致会一次加载所有原本不同的ViewType,无法使用懒加载避免这一现象;

而同时因为ViewType视图样式不同,肯定要重新inflate不同的视图样式,根本没有减少耗时。

RecyclerView缓存机制失效的情况

重写Adapter的onFailedToRecycleView

首先查看RecyclerView的源码:

在是否回收ViewHolder的判断中包含两个条件:boolean值forceRecycle和isRecyclable方法。我们首先查看后者代码:

后者的isRecyclable方法获取到的是一个名为TransientState的值(直译:临时状态)。当某个ViewHolder中的某个View在做属性动画时,这个值会属性动画开始和结束时被设置:

 

这么来说,如果一个ViewHolder在离开显示区时,同时内部有任意一个view在做属性动画,TransientState的值就会是false,isRecyclable方法返回的也是false,这个ViewHolder就无法被存储到缓存区或循环池中。

这种情况最容易出现在ViewHolder中存在循环属性动画的场景。如果没有对这个循环属性动画做处理,那么就会出现缓存机制失效的情况。如dy中的专辑旋转动画:

而是否回收ViewHolder的判断中,前者forceRecycle是根据onFailedToRecycleView方法设定的,我们可以重写这个方法:

override fun onFailedToRecycleView(holder: MyViewHolder?): Boolean {return true
}

onBindViewHolder中重置View的动画属性

为什么Android要设计ViewHolder中的View的属性动画不能被回收,要我们如此大费周章?

这么设计的原因是防止ViewHolder被复用时之前的动画状态被保留。因此我们可以在重新绑定ViewHolder的onBindViewHolder方法中,重置View的动画属性,如偏转角度(Rotation)、透明度(Alpha)等。

RecyclerView的特殊复用机制

循环池(mRecyclerPool)可以服务于多个RecyclerView。当其他RecyclerView中拥有循环池中相同的ViewType时,他们都可以使用这个循环池。

参考 

Android RecyclerView的缓存机制_哔哩哔哩_bilibili

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • C++11 新特性使用讲解【C++】
  • 安卓开发中的AppCompat框架|安卓系统|安卓应用|兼容性|UI组件|核心组件|ActionBar|Fragment|最佳实践|框架|移动开发|移动应用
  • 【STM32】DMA数据转运(存储器到存储器)
  • SSM电子商务系统-计算机毕业设计源码68470
  • 从源码分析 Redis 异步删除各个参数的具体作用
  • 【el-table】横向滚动条加粗后,滚动到固定列下被遮挡,已解决
  • Windows EFI 启动分区修复指南(Windows误删了EFI分区)
  • Facebook与区块链的合作前景:社交平台的未来愿景
  • C# 委托 (delegate)
  • Unity 中创建动画的教程
  • MNN部署、集成
  • ZLMediaKit编译webrtc
  • ogg格式如何转换成MP3?这6个方法真心不错
  • 红酒与户外探险:探险途中的很好伴侣
  • Java使用MQTT协议
  • 时间复杂度分析经典问题——最大子序列和
  • 〔开发系列〕一次关于小程序开发的深度总结
  • canvas 五子棋游戏
  • HTML中设置input等文本框为不可操作
  • iOS小技巧之UIImagePickerController实现头像选择
  • JavaScript HTML DOM
  • JAVA并发编程--1.基础概念
  • Java超时控制的实现
  • JAVA多线程机制解析-volatilesynchronized
  • Java深入 - 深入理解Java集合
  • PhantomJS 安装
  • PHP 7 修改了什么呢 -- 2
  • PHP那些事儿
  • 阿里云应用高可用服务公测发布
  • 程序员最讨厌的9句话,你可有补充?
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 批量截取pdf文件
  • 我建了一个叫Hello World的项目
  • 学习ES6 变量的解构赋值
  • 再次简单明了总结flex布局,一看就懂...
  • 走向全栈之MongoDB的使用
  • ​比特币大跌的 2 个原因
  • ​决定德拉瓦州地区版图的关键历史事件
  • #Java第九次作业--输入输出流和文件操作
  • #java学习笔记(面向对象)----(未完结)
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • $.ajax()参数及用法
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (2.2w字)前端单元测试之Jest详解篇
  • (42)STM32——LCD显示屏实验笔记
  • (52)只出现一次的数字III
  • (6)添加vue-cookie
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (WSI分类)WSI分类文献小综述 2024
  • (黑马C++)L06 重载与继承
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (推荐)叮当——中文语音对话机器人
  • (五)Python 垃圾回收机制
  • (一)springboot2.7.6集成activit5.23.0之集成引擎