Android RecyclerView 绘制流程及Recycler缓存

void dispatchLayout() {

mState.mIsMeasuring = false;

if (mState.mLayoutStep == State.STEP_START) {

dispatchLayoutStep1();

mLayout.setExactMeasureSpecsFrom(this);

//测量子 View

dispatchLayoutStep2();

} else if (mAdapterHelper.hasUpdates() || mLayout.getWidth() != getWidth()

|| mLayout.getHeight() != getHeight()) {

mLayout.setExactMeasureSpecsFrom(this);

//测量子 View

dispatchLayoutStep2();

} else {

mLayout.setExactMeasureSpecsFrom(this);

}

//触发动画效果

dispatchLayoutStep3();

}

如果在 onMeasure 阶段没有执行 dispatchLayoutStep2() 方法去测量子 View,则会在 onLayout 阶段重新执行。

dispatchLayoutStep2

//在此步骤中,我们对最终状态的视图进行实际布局。

//如有必要,可多次运行此步骤(例如,measure)。

private void dispatchLayoutStep2() {

// Step 2: Run layout

mState.mInPreLayout = false;

mLayout.onLayoutChildren(mRecycler, mState);

}

public void onLayoutChildren(Recycler recycler, State state) {

Log.e(TAG, "You must override onLayoutChildren(Recycler recycler, State state) ");

}

核心逻辑是调用了 mLayout 的 onLayoutChildren 方法。

这个方法在 RecyclerView.LayoutManager 中的一个空方法,主要作用是测量 RecyclerView 内的子 View 大小,并确定它们所在的位置。

LinearLayoutManager、GridLayoutManager,以及 StaggeredLayoutManager 都分别复写了这个方法,并实现了不同方式的布局。

LinearLayoutManager.onLayoutChildren

@Override

public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {

//调用 fill 方法,完成子 View 的测量布局工作;

fill(recycler, mLayoutState, state, false);

}

//重点

int fill(RecyclerView.Recycler recycler, LayoutState layoutState,

RecyclerView.State state, boolean stopOnFocusable) {

while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {

layoutChunkResult.resetInternal();

if (RecyclerView.VERBOSE_TRACING) {

TraceCompat.beginSection(“LLM LayoutChunk”);

}

//子 View 测量布局的真正实现,每次执行完之后需要重新计算 remainingSpace。

layoutChunk(recycler, state, layoutState, layoutChunkResult);

if (!layoutChunkResult.mIgnoreConsumed || layoutState.mScrapList != null

|| !state.isPreLayout()) {

layoutState.mAvailable -= layoutChunkResult.mConsumed;

// 我们保留一个单独的剩余空间,因为Mavaailable对于回收很重要

//每次循环之后,都将remainingSpace减去已消费的size

remainingSpace -= layoutChunkResult.mConsumed;

}

return start - layoutState.mAvailable;

}

在 onLayoutChildren 中调用 fill 方法,完成子 View 的测量布局工作;

在 fill 方法中通过 while 循环判断是否还有剩余足够空间来绘制一个完整的子 View;

layoutChunk 方法中是子 View 测量布局的真正实现,每次执行完之后需要重新计算 remainingSpace。

layoutChunk

layoutChunk 是一个非常核心的方法,这个方法执行一次就填充一个 ItemView 到 RecyclerView,部分代码如下:

void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,

LayoutState layoutState, LayoutChunkResult result) {

//从缓存(Recycler)中取出子 ItemView。

View view = layoutState.next(recycler);

RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();

//然后调用 addView 或者 addDisappearingView 将子 ItemView 添加到 RecyclerView 中。

if (layoutState.mScrapList == null) {

if (mShouldReverseLayout == (layoutState.mLayoutDirection

== LayoutState.LAYOUT_START)) {

addView(view);

} else {

addView(view, 0);

}

} else {

if (mShouldReverseLayout == (layoutState.mLayoutDirection

== LayoutState.LAYOUT_START)) {

addDisappearingView(view);

} else {

addDisappearingView(view, 0);

}

}

//测量被添加的 RecyclerView 中的子 ItemView 的宽高。

measureChildWithMargins(view, 0, 0);

//根据所设置的 Decoration、Margins 等所有选项确定子 ItemView 的显示位置。

layoutDecoratedWithMargins(view, left, top, right, bottom);

}

onDraw


测量和布局都完成之后,就剩下最后的绘制操作了。

@Override

public void onDraw(Canvas c) {

super.onDraw©;

final int count = mItemDecorations.size();

for (int i = 0; i < count; i++) {

mItemDecorations.get(i).onDraw(c, this, mState);

}

}

如果有添加 ItemDecoration,则循环调用所有的 Decoration 的 onDraw 方法,将其显示。至于所有的子 ItemView 则是通过 Android 渲染机制递归的调用子 ItemView 的 draw 方法显示到屏幕上。

绘制流程小结


RecyclerView 会将测量 onMeasure布局 onLayout 的工作委托给 LayoutManager 来执行,不同的 LayoutManager 会有不同风格的布局显示,这是一种策略模式。如下图:

缓存复用原理 Recycler

===============

缓存复用是 RecyclerView 中另一个非常重要的机制,这套机制主要实现了 ViewHolder 的缓存以及复用。

核心代码是在 Recycler 中完成的,它是 RecyclerView 中的一个内部类,主要用来缓存屏幕内 ViewHolder 以及部分屏幕外 ViewHolder,部分代码如下:

public final class Recycler {

//未与RecyclerView分离的ViewHolder列表

final ArrayList mAttachedScrap = new ArrayList<>();

//与RecyclerView分离的ViewHolder列表

ArrayList mChangedScrap = null;

//ViewHolder缓存列表

final ArrayList mCachedViews = new ArrayList();

//ViewHolder缓存池

RecycledViewPool mRecyclerPool;

//开发者可以控制的ViewHolder缓存的帮助类

private ViewCacheExtension mViewCacheExtension;

//默认情况下缓存个数是 2

static final int DEFAULT_CACHE_SIZE = 2;

}

Recycler 的缓存机制就是通过上图中的这些数据容器来实现的,实际上 Recycler 的缓存也是分级处理的,根据访问优先级从上到下可以分为 4 级,如下:

  • 第一级缓存 mAttachedScrap&mChangedScrap

  • 第二级缓存 mCachedViews

  • 第三级缓存 ViewCacheExtension

  • 第四级缓存 RecycledViewPool

各级缓存功能


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

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

小结

有了这么多优秀的开发工具,可以做出更高质量的Android应用。

当然了,“打铁还需自身硬”,想要写出优秀的代码,最重要的一点还是自身的技术水平,不然用再好的工具也不能发挥出它的全部实力。

在这里我也分享一份大佬自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。

总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习

、实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-u8Ahorjh-1710498309894)]

小结

有了这么多优秀的开发工具,可以做出更高质量的Android应用。

当然了,“打铁还需自身硬”,想要写出优秀的代码,最重要的一点还是自身的技术水平,不然用再好的工具也不能发挥出它的全部实力。

在这里我也分享一份大佬自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。

总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习

如果你有需要的话,可以点击这里领取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值