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移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
小结
有了这么多优秀的开发工具,可以做出更高质量的Android应用。
当然了,“打铁还需自身硬”,想要写出优秀的代码,最重要的一点还是自身的技术水平,不然用再好的工具也不能发挥出它的全部实力。
在这里我也分享一份大佬自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。
总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习
、实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-u8Ahorjh-1710498309894)]
小结
有了这么多优秀的开发工具,可以做出更高质量的Android应用。
当然了,“打铁还需自身硬”,想要写出优秀的代码,最重要的一点还是自身的技术水平,不然用再好的工具也不能发挥出它的全部实力。
在这里我也分享一份大佬自己收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料这些都是我闲暇还会反复翻阅的精品资料。在脑图中,每个知识点专题都配有相对应的实战项目,可以有效的帮助大家掌握知识点。
总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习
如果你有需要的话,可以点击这里领取