2024最新大厂Android面试集合,真正带你搞懂-RecyclerView-的缓存机制,Android校招面试经验汇总

我们先了解下Recycler的缓存结构是怎样的,先了解两个专业词汇:

  • Scrap (view):在布局期间进入临时分离状态的子视图。废弃视图可以重复使用,而不会与父级RecyclerView完全分离,如果不需要重新绑定,则不进行修改,如果视图被视为脏,则由适配器修改。(这里的脏怎么理解呢?就是指那些在展示之前必须重新绑定的视图,比如一个视图原来展示的是“张三”,之后需要展示“李四”了,那么这个视图就是脏视图,需要重新绑定数据后再展示的。)

  • Recycle (view):先前用于显示适配器特定位置的数据的视图可以放置在高速缓存中以供稍后重用再次显示相同类型的数据。这可以通过跳过初始布局或构造来显着提高性能。

RecyclerView的缓存类型呢基本也就是上面的两种,这时可能有同学要站出来说我不对了,胡说,RecyclerView明明有四级缓存,怎么就两种了,骚年稍安勿躁,且听我来慢慢分解。首先我们先看一个RV(RecyclerView在后文简称RV)的内部类Recycler。

public final class Recycler {
final ArrayList mAttachedScrap = new ArrayList<>();
ArrayList mChangedScrap = null;

final ArrayList mCachedViews = new ArrayList();
RecycledViewPool mRecyclerPool;
private ViewCacheExtension mViewCacheExtension;
…… 省略 ……
}

就是介个类掌握着RV的缓存大权,从上面的代码片段我们可以看到这个类声明了五个成员变量。我们一个个的来说一下:

  1. mAttachedScrap:我们可以看到这个变量是个存放ViewHolder对象的ArrayList,这一级缓存是没有容量限制的,只要符合条件的我来者不拒,全收了。前面讲两个专业术语的时候提到了Scrap,这个就属于Scrap中的一种,这里的数据是不做修改的,不会重新走Adapter的绑定方法。

  2. mChangedScrap:这个变量和上边的mAttachedScrap是一样的,唯一不同的从名字也可以看出来,它存放的是发生了变化的ViewHolder,如果使用到了这里的缓存的ViewHolder是要重新走Adapter的绑定方法的。

  3. mCachedViews:这个变量同样是一个存放ViewHolder对象的ArrayList,但是这个不同于上面的两个里面存放的是dettach掉的视图,它里面存放的是已经remove掉的视图,已经和RV分离的关系的视图,但是它里面的ViewHolder依然保存着之前的信息,比如position、和绑定的数据等等。这一级缓存是有容量限制的,默认是2(不同版本API可能会有差异,本文基于API26.1.0)。

  4. mRecyclerPool:这个变量呢本身是一个类,跟上面三个都不一样。这里面保存的ViewHolder不仅仅是removed掉的视图,而且是恢复了出厂设置的视图,任何绑定过的痕迹都没有了,想用这里缓存的ViewHolder那是铁定要重新走Adapter的绑定方法了。而且我们知道RV支持多布局,所以这里的缓存是按照itemType来分开存储的,我们来大致的看一下它的结构:

public static class RecycledViewPool {
private static final int DEFAULT_MAX_SCRAP = 5;
static class ScrapData {
ArrayList mScrapHeap = new ArrayList<>();
int mMaxScrap = DEFAULT_MAX_SCRAP;
…… 省略 ……
}
SparseArray mScrap = new SparseArray<>();
…… 省略后面代码 ……
}

  • 首先我们看到一个常量‘DEFAULT_MAX_SCRAP’,这个就是缓存池定义的一个默认的缓存数,当然这个缓存数我们是可以自己设置的。而且这个缓存数量不是指整个缓存池只能缓存这么多,而是每个不同itemType的ViewHolder的缓存数量。

  • 接着往下看,我们看到一个静态内部类ScrapData,这里我们只看跟缓存相关的两个变量,先说mMaxScrap,前面的常量赋值给了它,这也就印证了我们前面说的这个缓存数量是对应每一种类型的ViewHolder的。再来看这个mScrapHeap变量,熟悉的一幕又来了,同样是一个缓存ViewHolder对象的ArrayList,它的容量默认是5.

  • 最后我们看到mScrap这个变量,它是一个存储我们上面提到的ScrapData类的对象的SparseArray,这样我们这个RecyclerPool就把不同itemType的ViewHolder按类型分类缓存了起来。

mViewCacheExtension:这一级缓存是留给开发者自由发挥的,官方并没有默认实现,它本身是null。

垃圾桶讲完了,哦不,是缓存层级讲完了。这里提一句,其实还有一层没有提到,因为它不在Recycler这个类中,它在ChildHelper类中,其中有个mHiddenViews,是个缓存被隐藏的ViewHolder的ArrayList。到这里我想大家对这几层缓存心里已经有个数了,但是还远远不够,这么多层缓存是怎么工作的?什么时候用什么缓存?各个缓存之间有没有什么PY交易?如果让你自己写一个LayoutManager你能处理好缓存问题么?就好比垃圾分类后,我们知道每种垃圾桶的定义和功能,但是面对大妈的灵魂拷问我依然分不清自己是什么垃圾,我太难了~相比之下,RV的几个垃圾桶简单多了,下面我们一起来看看,这些个缓存都咋用。

各缓存的使用

上面我们介绍了RV的各缓存层级,但是它们是怎么工作的呢?为什么要设计这些层级呢?别急,我们去源码中找找答案。一叶落而知天下秋,我们就从官方自带的最简单的布局管理者LinearLayoutManager入手,来看看到底如何使用这几级缓存写出一个合格的布局管理者。

RV从无到有的加载过程

首先我们看一下RV从无到有是怎么显示出数据来的。大家因该知道一个视图的显示要经过onMeasure、onLayout、onDraw三个方法,那么我们就先从第一个方法onMeasure入手,来看看里面做了什么。

@Override
protected void onMeasure(int widthSpec, int heightSpec) {
if (mLayout == null) {
defaultOnMeasure(widthSpec, heightSpec);
return;
}
if (mLayout.mAutoMeasure) {
if (mState.mLayoutStep == State.STEP_START) {
dispatchLayoutStep1();
}
dispatchLayoutStep2();
}
}

上面代码省略了一些无关代码,我们只看我们关心的,dispatchLayoutStep1和2方法,1方法中如果mState.mRunPredictiveAnimations为true会调用mLayout.onLayoutChildren(mRecycler, mState)这个方法,但是一般RV的预测动画都为false,所以我们看一下2方法,方法中同样调用了mLayout.onLayoutChildren(mRecycler, mState)方法,来看一下:

//已省略无关代码
private void dispatchLayoutStep2() {
eatRequestLayout();
onEnterLayoutOrScroll();

// Step 2: Run layout
mState.mInPreLayout = false;
mLayout.onLayoutChildren(mRecycler, mState);

mState.mLayoutStep = State.STEP_ANIMATIONS;
onExitLayoutOrScroll();
resumeRequestLayout(false);
}

这里onLayoutChildren方法是必走的,而mLayout是RV的成员变量,也就是LayoutManager,接下来我们去LinearLayoutManager里看看onLayoutChildren方法做了什么。

//已省略无关代码
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {

detachAndScrapAttachedViews(recycler);

if (mAnchorInfo.mLayoutFromEnd) {
// fill towards start
fill(recycler, mLayoutState, state, false);

// fill towards end
fill(recycler, mLayoutState, state, false);
endOffset = mLayoutState.mOffset;
} else {

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

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

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

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后,如果大伙有什么好的学习方法或建议欢迎大家在评论中积极留言哈,希望大家能够共同学习、共同努力、共同进步。

小编在这里祝小伙伴们在未来的日子里都可以 升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰!!

不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

ava、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算**

  • 30
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值