仿探探划卡片 -- RecyclerView的四级缓存

本文详细解析了AndroidRecyclerView中四级缓存(包括一级、二级、三级和四级)的获取策略以及回收过程,重点介绍了如何通过Position或ID从缓存中获取ViewHolder,以及自定义LayoutManager时如何模仿LinearLayoutManager的回收和复用机制。
摘要由CSDN通过智能技术生成
  1. layoutState.next 根据mCurrentPosition去取View

  1. getViewForPosition

  1. tryGetViewHolderForPositionByDeadline,重点!!! 翻译(尝试获取ViewHolder根据Position 在有效期内)

tryGetViewHolderForPositionByDeadline – 重点–四级缓存取的重点

这个方法就是从缓存里取出ViewHolder的方法

他分几种情况去获取ViewHolder

1.getChangedScrapViewForPosition – mChangeScrap 与动画相关

2.getScrapOrHiddenOrCachedHolderForPosition – mAttachedScrap 、mCachedViews

3.getScrapOrCachedViewForId – mAttachedScrap 、mCachedViews (ViewType,itemid)

4.mViewCacheExtension.getViewForPositionAndType – 自定义缓存

5.getRecycledViewPool().getRecycledView – 从缓冲池里面获取

  1. getChangedScrapViewForPosition 获取ChangedScrapView通过Position

是从mChangeScrap的List里取的,一般与动画相关 — 一级缓存

通过position或者id取,都是for循环遍历List,然后出去holder,在if判断,如果符合条件就返回holder

  1. 如果没取到,if (holder == null),那就getScrapOrHiddenOrCachedHolderForPosition(获取Scrap/Hidden/Cached的Holder–For–Position)

**mAttachedScrap 、mCachedViews从这两列表里取,

mAttachedScrap=一级缓存,mCachedViews=二级缓存**

  1. 如果还是没取到,getScrapOrCachedViewForId,跟第二步一样,只不过第二步用的Position取,这个用的id取

**mAttachedScrap 、mCachedViews (ViewType,itemid)

mAttachedScrap=一级缓存,mCachedViews=二级缓存**

  1. 还没取到 mViewCacheExtension.getViewForPositionAndType 在自定义缓存里取,一般用不到

mViewCacheExtension三级缓存

  1. 还没取到去RecycledViewPool里取

RecycledViewPool是第四级缓存,他的构造上面说了

  1. 四级缓存都没取到,mAdapter.createViewHolder,那就调用mAdapter的createViewHolder去创建

  1. 创建了ViewHolder以后就得去绑定,tryBindViewHolderByDeadline

最后会调到自己写的Adapter中的onBindViewHolder

多级缓存的目的:肯定是为了性能

回收

回收就是当ItemView划出屏幕的时候,将ViewHolder存到集合(List)里。

  • LinearLayoutManager.onLayoutChildren --> detachAndScrapAttachedViews --> scrapOrRecycleView
  1. LinearLayoutManager.onLayoutChildren

onLayoutChildren这个方法其实跟onLayout差不多,但是onLayout需要处理很多代码,但是onLayoutChildren其实是简化了onLayout。

补充(onLayout会调到onLayoutChildren,如果自定义LayoutManager,那重写onLayoutChildren就省去很多onLayout的代码):

RecyclerView.onLayoutChildren里备注了,如果要自定义LayoutManager那就一定要实现这个方法,但是有点坑,谷歌应该定义成抽象的,缺没有

image.png

onLayoutChildren这个方法的起点就是onLayout()

  1. RecyclerView.detachAndScrapAttachedViews

image.png

  1. scrapOrRecycleView(废弃 or 回收 View)

  1. itemView的回收的主流程就在scrapOrRecycleView

scrapOrRecycleView

具体选择哪个缓存,scrap还是RecycleView

if (viewHolder.isInvalid()) 如果viewHolder被移出屏幕那就走

->recycler.recycleViewHolderInternal(viewHolder); (Internal内部)

else -> recycler.scrapView(view);

具体流程:

–> ①.recycler.recycleViewHolderInternal(viewHolder); – 处理 CacheView 、RecyclerViewPool 的缓存

  • –> 1.ViewHodler改变 不会进来 – 先判断mCachedViews的大小

–> mCachedViews.size 大于默认大小 — recycleCachedViewAt

– >addViewHolderToRecycledViewPool — 缓存池里面的数据都是从mCachedViews里面出来的

  • –> 2.addViewHolderToRecycledViewPool --> getRecycledViewPool().putRecycledView(holder);

–> scrap.resetInternal(); ViewHolder 清空

–> ②.recycler.scrapView(view);

recycler.recycleViewHolderInternal(viewHolder) – 处理 CacheView 、RecyclerViewPool 的缓存(scrapOrRecycleView方法里的 if 分支)
  1. 先判断mCachedViews列表的大小是不是大于规定的最大值mViewCacheMax,大于的话就走recycleCachedViewAt()

image.png

  1. 不管mCachedViews大小有没有超最大值,都会将holder,add进mCachedViews列表

  1. 看如果超过最大mViewCacheMax的recycleCachedViewAt方法

注意入参是0

**1.先 ViewHolder viewHolder = mCachedViews.get(cachedViewIndex);

2.将取出的viewHolder,传入addViewHolderToRecycledViewPool(viewHolder, true);–顾名思义:添加ViewHolder到缓存池

3.将mCachedViews.remove(cachedViewIndex)**

image.png

总结:

  1. addViewHolderToRecycledViewPool

  1. putRecycledView

所以RecycledViewPool里面的ViewHolder是个空的,但是mCachedViews列表里的ViewHolder却是有数据的ViewHolder

recycler.scrapView(view) (scrapOrRecycleView方法里的 else 分支)

如果不是划出屏幕的缓存

其实就很简单了,直接往mAttachedScrap或者mChangedScrap列表里add(holder),第一级缓存

总结

缓存与复用

仿探探划卡片


效果:

实现自定义LayoutManager

先实现一个

这就没啥好说的。

重点在于自定义LayoutManager,之前使用的是系统的LinearLayoutManager

  1. 继承RecyclerView.LayoutManager

自定义LayoutManager,都是需要继承这个的

  1. 继承完以后发现有一个方法要实现

设置默认的LayoutParams

查看LinearLayoutManager是怎么做的

直接复制过来就行,自己的也这样实现

  1. onLayout必须实现,上面有说过,要自定义LayoutManager必须要实现onLayoutChildren,谷歌写的log里说的,但是他没给弄成抽象

  1. 在onLayoutChildren主要实现的就是布局onLayout,还有参考LinearLayoutManager他还实现了RecyclerView四级缓存的回收、复用都实现了。

回收:看上面源码分析的步骤,回收里调用的是detachAndScrapAttachedViews

image.png

查看LinearLayoutManager源码,复用其实也有调用到,fill()方法

fill一直往下点(看上面源码分析:)

–> fill --> layoutChunk --> layoutState.next --> addView(view); image.png

layoutState.next。这个就是跳出LinearLayoutManager执行到RecyclerView的方法。

是一个while循环然后遍历,在.next取出各个View,通过

final View view = recycler.getViewForPosition(mCurrentPosition);

**所以我们自己写自定义LayoutManager的onLayoutChildren的时候,回收复用就仿照LinearLayoutManager来

回收=detachAndScrapAttachedViews

复用=for遍历然后通过position取出View,最后在addView,

View view = recycler.getViewForPosition(mCurrentPosition)这个**

  1. 回收复用写完

算上被划走的那张卡片,其实只需要布局4张卡片


自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

这里我特地整理了一份《Android开发核心知识点笔记》,里面就包含了自定义View相关的内容

除了这份笔记,还给大家分享 Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

分享上面这些资源,希望可以帮助到大家提升进阶,如果你觉得还算有用的话,不妨把它们推荐给你的朋友~

喜欢本文的话,给我点个小赞、评论区留言或者转发支持一下呗~

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

:Android)**

最后

这里我特地整理了一份《Android开发核心知识点笔记》,里面就包含了自定义View相关的内容

[外链图片转存中…(img-Fr1y7tvp-1712370225955)]

除了这份笔记,还给大家分享 Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

[外链图片转存中…(img-xDXihNL7-1712370225955)]

分享上面这些资源,希望可以帮助到大家提升进阶,如果你觉得还算有用的话,不妨把它们推荐给你的朋友~

喜欢本文的话,给我点个小赞、评论区留言或者转发支持一下呗~

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 27
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值