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結把榮偶瀝燥芹翎荸?