开题前,笔者还是要说几句先,依旧和前文一样,文章内不涉及源码讲解,默认各位读者对源码有一定的了解,撰文的原因也如同前文,因为笔者认为当下在 ListView/RecyclerView 的源码讲解的文章中,大都是对着源码噼里啪啦,实在有些晦涩难懂,于是笔者想将部分数据可视化,手摸手带领读者去了解一下缓存机制的实现,另推荐阅读腾讯 Bugly 的《Android ListView与RecyclerView对比浅析–缓存机制》一文。
1.前文地址:《可视化 ListView 缓存机制,手摸手带你打通任督二脉》
2.本文项目地址:RecyclerViewVisualization 或直接下载 apk
希望阅读本文前请先阅读前文,本文所涉及的一些关键字在上文有所提及。
一缓
手摸手打开 app:
RecyclerView 中的一缓 mAttachedScrap 与 ListView 中的一缓 mActiveViews 功能是基本相似的,为了屏幕内 item 快速复用而存在(RecyclerView/ListView 具有两次 onLayout() 过程,第二次 onLayout() 中直接使用第一次 onLayout() 缓存的 View,而不必再创建)。
二缓
实际上,二缓 mCachedViews 加上四缓 RecyclerViewPool 合在一起与 ListView 的二缓 mScrapedViews 意义相同,为了即将给即将入屏的 item 复用而存在。下面来细谈下二缓:
- ArrayList 类型
- 默认 size 为 2
- size 可变
- 复用算法是从尾部倒序匹配 ViewHolder position 与传入的 position 是否相等,匹配成功则返回
- 为了优化上一步,下一个可能出现的 item 将会被置于尾部
二缓是通过 position 来匹配相应的 ViewHolder 的,这里的 position 指的是 RecyclerView 预测的、可能进入屏幕的 item 的 position,它是由当前屏幕滑动方向和可见的 item 位置来共同决定的。例如:屏幕向下滑动,那么可能进入屏幕的 item 的 position 就是当前可见第一个 item 的 position - 1;屏幕向上滑动,那么可能进入屏幕的 item 的 position 就是当前可见的最后一个 item 的 position + 1。这样说起来可能有些模糊,举个例子:
以上述状态来说,如果屏幕下滑,那么预测下一个可能出现在屏幕上的 item 的 position 可能是 4(也就是 Item1『E(layoutPosition:4)』);而如果屏幕上滑,预测的下一个出现在屏幕上的 item 的 position 是 0(也就是 Item『A(layoutPosition:0)』)。然后通过将 position 用于与 mCacheViews 中的 ViewHolder 的 layoutPosition 做比较,如果相同则返回该 ViewHolder。
来看动图:
1.屏幕上滑:
可以看到 target mCacheView position 由 0 变成了 4。与此同时,mCachedViews 将可能出现在屏幕上的 item 的位置从原有的位置调整为 ArrayList 的最后一位。
2.屏幕下滑:
屏幕下滑的话,target mCachedView position 由 4 变成了 0。与此同时,mCachedViews 内部也会做相应的调整。
四缓
四缓(RecycledViewPool)性质:
-
内部维护了一个 SparseArray
-
SparseArray key 为 ViewHolder 的 ViewType,这说明每一套 ViewHolder 都具有自己的缓存数据
-
SparseArray value 为 ScrapData 类型,ScrapData 就是关键的缓存数据了,其数据结构简略如下:
static class ScrapData {
ArrayList mScrapHeap = new ArrayList<>();
int mMaxScrap = 5;
// …
}
由此可见,针对每一种 ViewHolder,RecycledViewPool 都会维护一个默认大小为 5 的 ArrayList 来用做缓存它们,当然,这里还需要提及的一点是,ArrayList 的默认大小被限制为 5,但是这个值是可以通过 RecycledViewPool#setMaxRecycledViews(viewType, max)
来替换的,比如想换成大一点的 10、20,都是可以的(这也是该数据类型为 ArrayList 而不是数组的原因之一)。
前面说到——“实际上,二缓 mCachedViews 加上四缓 RecyclerViewPool 合在一起与 ListView 的二缓 mScrapedViews 意义相同,为了即将给即将入屏的 item 复用而存在。”,可能有小伙伴疑惑了,既然意义相同,为何不是只有二缓就足够了,还要多一个四缓来更复杂?缘由在于:可以由开发者主动向内填充数据(RecycledViewPool#putRecycledView(ViewHolder)
),技术上可以实现多个 RecyclerView 共用同一个 RecyclerViewPool(RecyclerView#setRecycledViewPool(RecycledViewPool)
)。这两点在笔者看来,是在某种业务场景下选择 RecyclerView 还是 ListView 的一个重要缘由所在。至于这两点的实践,第一点笔者已经添加在 Demo 中了(含彩蛋),第二点笔者就不在此处扩展了,各位读者可以自行添加入 RecyclerViewVisualization Demo 中,相应的数据也都会被展示到屏幕上~
其他
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
下图是我进阶学习所积累的历年腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节
整理不易,望各位看官老爷点个关注转发,谢谢!祝大家都能得到自己心仪工作。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!**