RecyclerView緩存機制

緩存層級(緩存結(jié)構(gòu)/緩存類型)

  • ScrapView(臟視圖):
    • 布局期間進入臨時分離狀態(tài)的子視圖
    • 可以重復(fù)使用珊膜,而不會與父級RecyclerView完全分離灵奖,如果不需要重新綁定嚼沿,則不進行修改如果視圖被視為臟,則由適配器修改瓷患。
    • RV展示成功后骡尽,Scrap這層的緩存就為空了,在從Scrap中取視圖的同時就被移出了緩存

這里的臟怎么理解呢擅编?就是指那些在展示之前必須重新綁定的視圖攀细,比如一個視圖原來展示的是“張三”,之后需要展示“李四”了爱态,那么這個視圖就是臟視圖谭贪,需要重新綁定數(shù)據(jù)后再展示的。

  • RecyclerView(回收視圖):
    • 先前用于顯示適配器特定位置的數(shù)據(jù)的視圖可以放置在高速緩存中以供稍后重用再次顯示相同類型的數(shù)據(jù)

這可以通過跳過初始布局或構(gòu)造來顯著提高性能

緩存變量

Recycler中的緩存變量

  • mAttachedScrap
    • Scrap中的一種锦担,這里的數(shù)據(jù)是不做修改的俭识,不會重新走Adapter的綁定方法
    • 沒有容量限制的,只要符合條件的我來者不拒洞渔,全收了
final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
  • mChangedScrap
    • Scrap中的一種
    • 存放的是發(fā)生了變化的ViewHolder,如果使用到了這里的緩存的ViewHolder是要重新走Adapter的綁定方法的套媚。
ArrayList<ViewHolder> mChangedScrap = null;
  • mCachedViews
    • 屬于Recycler(View),
    • remove掉的視圖磁椒,已經(jīng)和RV分離的關(guān)系的視圖凑阶,但是它里面的ViewHolder依然保存著之前的信息,比如position衷快、和綁定的數(shù)據(jù)等等
    • 緩存是有容量限制的,默認是2(不同版本API可能會有差異)
final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>();
  • mViewCacheExtension
    • 開發(fā)者自由發(fā)揮的姨俩,官方并沒有默認實現(xiàn)蘸拔,它本身是null。
private ViewCacheExtension mViewCacheExtension;
  • mRecyclerPool
    • 保存的ViewHolder不僅僅是removed掉的視圖环葵,而且是恢復(fù)了出廠設(shè)置的視圖调窍,任何綁定過的痕跡都沒有了,想用這里緩存的ViewHolder那是鐵定要重新走Adapter的綁定方法了
    • 按照itemType來分開存儲的
RecycledViewPool mRecyclerPool;

ChildHelper中的緩存變量

  • mHiddenViews
    • 緩存被隱藏的ViewHolder
final List<View> mHiddenViews = new ArrayList<View>();

RecyclerView的復(fù)用流程

最終調(diào)用到Recycler的tryGetViewHolderForPositionByDeadline方法

//第一步
if (mState.isPreLayout()) {
    holder = getChangedScrapViewForPosition(position);
    fromScrapOrHiddenOrCache = holder != null;
}
//第二步
if (holder == null) {
    holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
    //分三個流程
    1.從mAttachedScrap中查找
    2.ChildHelper類中的mHiddenViews中查找
    3.從mCachedViews中查找的
}
//第三步
if (holder == null && mViewCacheExtension != null) {
    final View view = mViewCacheExtension.getViewForPositionAndType(this, position, type);
    if (view != null) {
        holder = getChildViewHolder(view);
    }
}
//第四步
if (holder == null) {
    holder = getRecycledViewPool().getRecycledView(type);
}
//第五步
if (holder == null) {
    holder = mAdapter.createViewHolder(RecyclerView.this, type);
}
//最后
if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
    ...
    final int offsetPosition = mAdapterHelper.findPositionOffset(position);
    bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);
    //最終調(diào)用 mAdapter.bindViewHolder(holder, offsetPosition);
    ...
}
  • 第一步:getChangedScrapViewForPosition(position)方法中找需要的視圖张遭,但是有個條件mState.isPreLayout()要為true邓萨,這個一般在我們調(diào)用adapter的notifyItemChanged等方法時為true,其實也很好理解,數(shù)據(jù)發(fā)生了變化缔恳,viewholder被detach掉后緩存在mChangedScrap之中宝剖,在這里拿到的viewHolder后續(xù)需要重新綁定
if (mState.isPreLayout()) {
    holder = getChangedScrapViewForPosition(position);
    fromScrapOrHiddenOrCache = holder != null;
}
  • 第二步:如果沒有找到視圖則從getScrapOrHiddenOrCachedHolderForPosition這個方法中繼續(xù)找。
    • 首先從mAttachedScrap中查找
    • 再次從前面略過的ChildHelper類中的mHiddenViews中查找
    • 最后是從mCachedViews中查找的
if (holder == null) {
    holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
}

ViewHolder getScrapOrHiddenOrCachedHolderForPosition(int position, boolean dryRun) {
    //1.從mAttachedScrap中查找
    for (int i = 0; i < scrapCount; i++) {
        final ViewHolder holder = mAttachedScrap.get(i);
        return holder;
    }
    //2.ChildHelper類中的mHiddenViews中查找
    if (!dryRun) {
        //最終調(diào)用 final View view = mHiddenViews.get(i);
        View view = mChildHelper.findHiddenNonRemovedView(position);
        if(view != null) {
            final ViewHolder vh = getChildViewHolderInt(view);
            return vh;
        }
    }
    //3.mCachedViews中查找
    final int cacheSize = mCachedViews.size();
    for (int i = 0; i < cacheSize; i++) {
        final ViewHolder holder = mCachedViews.get(i);
        return holder
    }
}
  • 第三步:mViewCacheExtension中查找歉甚,我們說過這個對象默認是null的万细,是由我們開發(fā)者自定義緩存策略的一層,所以如果你沒有定義過纸泄,這里是找不到View的
if (holder == null && mViewCacheExtension != null) {
    ...
    final View view = mViewCacheExtension.getViewForPositionAndType(this, position, type);
    if (view != null) {
        holder = getChildViewHolder(view);
    }
    ...
}
  • 第四步:從RecyclerPool中查找赖钞,前面我們介紹過RecyclerPool,先通過itemType從SparseArray類型的mscrap中拿到ScrapData,不為空繼續(xù)拿到scrapHeap這個ArrayList聘裁,然后取到視圖雪营,這里拿到的視圖需要重新綁定
if (holder == null) {
    holder = getRecycledViewPool().getRecycledView(type);
}
  • 第五步:創(chuàng)建ViewHolder
if (holder == null) {
    holder = mAdapter.createViewHolder(RecyclerView.this, type);
}
  • 最后:綁定ViewHolder
if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
    ...
    final int offsetPosition = mAdapterHelper.findPositionOffset(position);
    bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);
    ...
}
private boolean tryBindViewHolderByDeadline(ViewHolder holder, int offsetPosition, int position, long deadlineNs) {
    ...
    mAdapter.bindViewHolder(holder, offsetPosition);
    ...
}

RecyclerView的回收流程

。衡便。献起。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市砰诵,隨后出現(xiàn)的幾起案子征唬,更是在濱河造成了極大的恐慌,老刑警劉巖茁彭,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件总寒,死亡現(xiàn)場離奇詭異,居然都是意外死亡理肺,警方通過查閱死者的電腦和手機摄闸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妹萨,“玉大人年枕,你說我怎么就攤上這事『跬辏” “怎么了熏兄?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長树姨。 經(jīng)常有香客問我摩桶,道長,這世上最難降的妖魔是什么帽揪? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任硝清,我火速辦了婚禮,結(jié)果婚禮上转晰,老公的妹妹穿的比我還像新娘芦拿。我一直安慰自己士飒,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布蔗崎。 她就那樣靜靜地躺著酵幕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚁趁。 梳的紋絲不亂的頭發(fā)上裙盾,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音他嫡,去河邊找鬼番官。 笑死,一個胖子當著我的面吹牛钢属,可吹牛的內(nèi)容都是我干的徘熔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼淆党,長吁一口氣:“原來是場噩夢啊……” “哼酷师!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起染乌,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤山孔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后荷憋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體台颠,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年勒庄,在試婚紗的時候發(fā)現(xiàn)自己被綠了串前。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡实蔽,死狀恐怖荡碾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情局装,我是刑警寧澤坛吁,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站铐尚,受9級特大地震影響拨脉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜塑径,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望填具。 院中可真熱鬧统舀,春花似錦匆骗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闷串,卻和暖如春瓮钥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背烹吵。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工碉熄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肋拔。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓锈津,卻偏偏與公主長得像,于是被迫代替她去往敵國和親凉蜂。 傳聞我的和親對象是個殘疾皇子琼梆,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容