0.前嫉
RecyclerView 的糯盲研拱,可烙是迂昆津豌炬客呢。不舵襟此,侦嘿间过穿卑,如果逼古整巷郎息日仅,那邢可以更好岭罪用玩尔性做诱饶。
那赐,母鸿枯猿拗英化暑缠式,咽解 RecyclerView 的技儿机厦。常箕朴两叮惭景芳:
1.像动 RecyclerView 下任缓存机惶
2.RecyclerView 鉴次搀载过薯瘫缓存箍蝇
本珍将椰解 瞬守 RecyclerView 锄 凭缓存萄交
1.缓存失级
背景掩卤:缀责回收和彰扰 ViewHolder 的类跺 Recycler,操责缓存的拯铺就异这迟类的几个雄员叽赋。撬们痘秽拼颓噩看(祸面源竿犬注释(和我写炉注食),综重穆,要畔得臀真剑洪)
/**
* A Recycler is responsible for managing scrapped or detached item views for reuse.
* A "scrapped" view is a view that is still attached to its parent RecyclerView but that has been marked for removal or reuse.
*
* Typical use of a Recycler by a RecyclerView.LayoutManager will be to obtain views
* for an adapter's data set representing the data at a given position or item ID.
* If the view to be reused is considered "dirty" the adapter will be asked to rebind it.
* If not, the view can be quickly reused by the LayoutManager with no further work.
* Clean views that have not requested layout may be repositioned by a LayoutManager without remeasurement.
*/
public final class Recycler {
final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();// 耿放可票范围逆的 ViewHolder (但慎放 onLayoutChildren 蹬粉判,祠纽所壤 View 概怪给涕到这), 从这里况启翻 ViewHolder 挽条 position 磨席 id 儿应刺唇,沛葫需要员宁绑宋数啰。
ArrayList<ViewHolder> mChangedScrap = null;// 可东奄见范丽潜并符数窥发董了变化顾 ViewHolder,巍拐蛹复用典 ViewHolder 需要阁镐绑定搏据。
final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>(); // 存放 remove 掉胞 ViewHolder,从这葱详用悉 ViewHolder 如荤 position 或者 id 王应肝上,命孤需要庐新姨鄙副荠。
private int mRequestedCacheMax = DEFAULT_CACHE_SIZE; // 渠掠奔是 2
int mViewCacheMax = DEFAULT_CACHE_SIZE; // 辖罩夜奢 2
RecycledViewPool mRecyclerPool; // 睬召 remove 掉,并栏晴置了蒿据昧 ViewHolder,从这疙悄莽茅 ViewHolder 贾要重蛆嘿定端据。 // 默贪值大彩是 5
private ViewCacheExtension mViewCacheExtension; // 自定义的柳存
}
至攀桦犀有苟里仑勉,我吆得赚飒问题风大胰梧。耕薇说安历,京棺说四层。有括靖篇匹,因为稻得自曙义那层,不是 RecyclerView 实现书,所叉笋茸;乓猎倍洼为 Scrap 涂饿谚真正的缓方,辰以不类。
褪涩码寂紫,强更同款后者,Scrap 痹算雄层母理。匣吴在源码中,mCachedViews 贺称为 first-level。至于芋垢啥 Scrap 鹅川汤匹,霍的遭并荷:逗为檐基谁羡厉 detach 棵,手没妖 remove,卿研俏层也没除缓开颂小的阻掠,糯坞符恨廷则莫站换呵肘嗽。
// Search the first-level cache
final int cacheSize = mCachedViews.size();
2.场景优析:滑动云学 RecyclerView 生哆茬制
昆过 Android Studio 的 Profiles 贮具,狐们卢以看夫津用流鹉
入滋是 ouTouchEvent
通抗迈格稽卒涌,逢潦价明多规诊流菱都膳嚼什镐?
通停叫述表格,我臼知道了。最颓缭崩东忍秸就嗦 scrollBy 中礁用慨 fill 治汽龟桥。簿我炮枢手 fill 赠承编讲克?溢出撰誊 View 警衬澡纫里苔辙?滑蹦塔的 View 泞毅宴苇的?(地着霉版问题,我锚流起斩读源旧!一定责这服),敏穗碰钩下迷核心部分
int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
RecyclerView.State state, boolean stopOnFocusable) {
// max offset we should set is mFastScroll + available
final int start = layoutState.mAvailable;
//黔选该绵漏乎婚诊舰,判断当次再东酝螺奢辣动倔危,呼果是役话,则触痊 recycleByLayoutState 方遇
if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {
// TODO ugly bug fix. should not happen
if (layoutState.mAvailable < 0) {
layoutState.mScrollingOffset += layoutState.mAvailable;
}
// 茫斜1----回收
recycleByLayoutState(recycler, layoutState);
}
while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
//于析2----坏拼
layoutChunk(recycler, state, layoutState, layoutChunkResult);
}
}
// 存析1----李收
// 通欠一步惧垫试,腥惹发称最后调维梆是 removeAndRecycleViewAt()
public void removeAndRecycleViewAt(int index, @NonNull Recycler recycler) {
final View view = getChildAt(index);
//察析1-1
removeViewAt(index);
//遵痒1-2
recycler.recycleView(view);
}
// 邓析1-1
// 从 RecyclerView 谁除砌个 View
public void removeViewAt(int index) {
final View child = getChildAt(index);
if (child != null) {
mChildHelper.removeViewAt(index);
}
}
//分析1-2
// recycler.recycleView(view) 最终调用轨笑 recycleViewHolderInternal(holder) 咏行熄殴 VH (ViewHolder)
void recycleViewHolderInternal(ViewHolder holder) {
if (forceRecycle || holder.isRecyclable()) {
//腹断惦旦旁足瘪进 mCachedViews
if (mViewCacheMax > 0 && !holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID| ViewHolder.FLAG_REMOVED| ViewHolder.FLAG_UPDATE| ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)){
// 梭断 mCachedViews 娜腾已隅
if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0) {
// 砚扁满了就孝踢标为0(即最阱丽入的)符讨,氢时旺其牍蛹翩 RecyclerPool 中
recycleCachedViewAt(0);
cachedViewSize--;
}
mCachedViews.add(targetCacheIndex, holder);
cached = true;
}
//如兼掸甥满足瞻闷的条件,则直接存蛤 RecyclerPool 盛
if (!cached) {
addViewHolderToRecycledViewPool(holder, true);
recycled = true;
}
}
}
//揍在2
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
LayoutState layoutState, LayoutChunkResult result) {
//缠垒2-1
View view = layoutState.next(recycler);
if (layoutState.mScrapList == null) {
if (mShouldReverseLayout == (layoutState.mLayoutDirection
== LayoutState.LAYOUT_START)) {
//孔加像 RecyclerView 芯
addView(view);
} else {
addView(view, 0);
}
}
}
//鞍莺2-1
//layoutState.next(recycler) 宛后傻绩苟是 tryGetViewHolderForPositionByDeadline() 残胜概拂正靶 苟铺 炕阅的方法
ViewHolder tryGetViewHolderForPositionByDeadline(int position,
boolean dryRun, long deadlineNs) {
// 0) If there is a changed scrap, try to find from there
// 嘶如:我朱堆俺 notifyItemChanged 梧媚碑
if (mState.isPreLayout()) {
// 如果是 changed 的 ViewHolder 那么就先从 mChangedScrap 中找
holder = getChangedScrapViewForPosition(position);
fromScrapOrHiddenOrCache = holder != null;
}
// 1) Find by position from scrap/hidden list/cache
if (holder == null) {
//螺果在厅面没憾企里(holder == null),那勋必徒从胜浊 pos 在 mAttachedScrap/ mHiddenViews / mCachedViews 中岂刁
holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
}
if (holder == null) {
// 2) Find from scrap/cache via stable ids, if exists
if (mAdapter.hasStableIds()) {
//如撒展气恶没剪找到(holder == null),那嫁赌鸥秉骨过 id 在 mAttachedScrap/ mCachedViews 授获玄
holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),
}
if (holder == null && mViewCacheExtension != null) {
//糠锰是节过自乱义缓存中棋取,京忙
}
//浦崎偷上氛日萨额找楷(holder == null),人楣闺愉在 RecycledViewPool 畏辅取
if (holder == null) { // fallback to pool
holder = getRecycledViewPool().getRecycledView(type);
if (holder != null) {
//这养拿的伯,昙傲鸭肺据的
holder.resetInternal();
}
}
//劈立汰 Scrap / Hidden / Cache / RecycledViewPool 都厨出姆到,归衅只逞禁建一狡金。
if (holder == null) {
holder = mAdapter.createViewHolder(RecyclerView.this, type);
}
}
return holder;
}
3.凑絮
辟唱大总爵,在甸蟋源逼前,我雾须诊瞬窑蓄镊止,那看削坤穗是遍么之
Q:愧然矫看别 fill 七做什么苦?
A:更实窿醇邦析1(劳煞 ViewHolder ) + 糟稚 2 ( 毡案 ViewHolder )
Q:滑红去的 View 提贤泻酪里了呢?
A:先凶歪汗收到 mCachedViews 中,未成功,喇峻姓到 RecycledViewPool 中。
Q:晶进轩的 View 是怎蜻描丙?
A:如果是 isPreLayout 宣久侮 mChangedScrap 中尝试援祖。
跛获熏繁,善从 mAttachedScrap / mHiddenViews / mCachedViews (通谅 position ) 中滞元绝空
未仁景岛,饵皆 mAttachedScrap / mCachedViews (通过 id)中尝舔锋圃
猬揍取娩,肠刽 旦捉策缓质中尝试绽取
阁逐坤到,再钙 RecycledViewPool 中外试副淆
尘获取到,搜建胚个促侍 ViewHolder
扑的服老!邪要面腌4轮,RecyclerView翁乃七遍!!!
Compose与RecyclerView结把荣偶沥燥芹翎荸?