RecyclerView內(nèi)部緩存Recycler

Recycler 只被RecyclerView持有杨帽。
Recycler 被回收的ViewHolder人柿,實(shí)際上是放入了RecyclerViewPool里面达传。
Recycler 只會(huì)操作ViewHolder碌更,不去操作具體的View瓶籽,即使在某些情況下傳入view恃鞋,也是通過view去找到與之對(duì)應(yīng)的holder崖媚。

Recycler的緩存分三級(jí)亦歉,一級(jí)緩存保存在列表的數(shù)據(jù),第二級(jí)是根據(jù)使用者是否配置來確定畅哑,三級(jí)緩存則是緩存池肴楷。
一級(jí)緩存分兩種,被廢棄的view(Scrap View)荠呐,被回收的View(RecycledView)

被廢棄的view(Scrap View)緩存

mAttachedScrap:其添加holder的地方為scrapView(); 條件 可重用的holder赛蔫、已移除的holder失效的holder泥张、不是Update的holder呵恢。
mChangedScrap:與mAttachedScrap同樣在scrapView()里面添加數(shù)據(jù),只要不是上述情況就加入到這里面;
以上兩種方法都是在unscrapView()方法里面對(duì)緩存進(jìn)行移除媚创。判斷條件為holder.mInChangeScrap.

被回收的View(RecycledView)緩存

mCachedViews:添加緩存的方法recycleViewHolderInternal()瑰剃,根據(jù)holder 可回收或強(qiáng)制回收,同時(shí)要保證最大可緩存數(shù)大于0筝野,holder的標(biāo)志必須 是FLAG_INVALID晌姚、FLAG_REMOVED、FLAG_UPDATE歇竟、FLAG_ADAPTER_POSITION_UNKNOWN之一挥唠,則會(huì)加入到緩存列表mCachedViews;不符合上述條件焕议,那么則直接加入到RecycledViewPool緩存池宝磨。要注意的是,雖然mCachedViews是ArrayList盅安,但是它不是無限制了添加holder唤锉,有一個(gè)maxCachedSize對(duì)它做了限制。
而從mCachedViews里移除holder時(shí)别瞭,一般會(huì)將其添加到RecycledViewPool 回收池里窿祥。holder在加入緩存池的時(shí)候,holder會(huì)與所屬的RecyclerView解除關(guān)聯(lián)蝙寨,還會(huì)將holder所有設(shè)置過的數(shù)據(jù)設(shè)置回初始狀態(tài)晒衩,另一種移除的情況是加入到RecyclerView展示的情況。

那么RecyclerView 根據(jù)什么判定用廢棄還是回收呢墙歪?
看看recycleViewHolderInternal 與 scrapView 各自調(diào)用的地方. 最后在LayoutManger里找到了關(guān)鍵代碼听系,
RecyclerView.LayoutManger.scrapOrRecycleView(), 它調(diào)用鏈:onLayoutChildren()=> detachAndScrapAttachedViews() => scrapOrRecycleView()虹菲,
見下代碼:

  private void scrapOrRecycleView(Recycler recycler, int index, View view) {
            final ViewHolder viewHolder = getChildViewHolderInt(view);
            ...
            if (viewHolder.isInvalid() && !viewHolder.isRemoved()
                    && !mRecyclerView.mAdapter.hasStableIds()) {
                removeViewAt(index);
                recycler.recycleViewHolderInternal(viewHolder);
            } else {
                detachViewAt(index);
                recycler.scrapView(view);
                mRecyclerView.mViewInfoStore.onViewDetached(viewHolder);
            }
        }

很明顯靠胜,被回收的是:holder失效 && 未移除 && hasStableIds未設(shè)置為true,
其他情況,被廢棄浪漠。
其上還有兩個(gè)函數(shù)要關(guān)注一下:removeViewAt(index)菠赚、detachViewAt(index),他們的內(nèi)部都由ChildHelpter去執(zhí)行具體的操作郑藏,相同點(diǎn)都會(huì)從mBucket里將view移除衡查,不同點(diǎn)在于:removeViewAt(index)還會(huì)將index的view從mHiddenViews移除的動(dòng)作。 由于ChildHelper內(nèi)部維護(hù)了可見\不可見兩列表必盖,而scrap方式不去刪除不可見表的數(shù)據(jù)拌牲,因此其復(fù)用性要高一些,這也是后文獲取緩存的緩存為什么scrap在前的原因歌粥。

關(guān)于緩存池 RecyclerViewPool

緩存池塌忽,保存holder根據(jù)getItemViewType()類別分別保存,它也是有存儲(chǔ)個(gè)數(shù)限制的失驶,默認(rèn)每個(gè)type保存最大限制個(gè)數(shù)為5個(gè)土居。
mScrap:以type作為key 保存對(duì)應(yīng)類型的緩存列表。
ScrapData:緩存列表的載體嬉探,mScrapHeap才是真正的列表擦耀。同時(shí)它還保存了緩存的最大時(shí)長。

獲取緩存過程

前面分析了holder是怎么緩存的涩堤,下面看看它是怎么從各級(jí)緩存里面將數(shù)據(jù)拿出來的眷蜓。
關(guān)鍵代碼點(diǎn):Recycler.tryGetViewHolderForPositionByDeadline()
查找緩存順序

  • 在預(yù)布局狀態(tài),如果有改變的, 就從 mChangeScrap里面找尋胎围。
  • 沒到找吁系,根據(jù)位置position去找,從mAttachedScrap里面去找白魂,沒有還要去ChildHelper里面的不可見列表找汽纤,還找不到,去mCachedViews里面未失效找對(duì)應(yīng)的位置的holder福荸。
  • 沒找到蕴坪,根據(jù)adapter.getItemId(),再從mAttachedScrap逞姿,再從mCachedViews里找辞嗡。
  • 還沒找到,若配置了mViewCacheExtension對(duì)象滞造,則從這里去找,一定會(huì)找到栋烤,找不到就會(huì)throw谒养,若不配置則沒有該步驟。
  • 還沒找到,最后到緩存池里找买窟,
  • 最后都沒有找到丰泊,放棄治療了,自己去創(chuàng)建一個(gè)viewHolder始绍。

并不是這里找到了viewHolder就可以直接使用瞳购,需要對(duì)該holder設(shè)置一部分屬性:
holder.mPreLayoutPosition,如果是預(yù)布局狀態(tài)并且已綁定了view 才需要亏推;
bound:holder未與RecyclerView学赛、adapter綁定的情況,將mAdater與holder綁定吞杭,tryBindViewHolderByDeadline()盏浇。這種場景是從緩存池里取出的,因?yàn)樵诖嫒氲臅r(shí)候是解除了關(guān)系并將holder設(shè)置回了初始狀態(tài)芽狗,我們熟悉的ViewHolder.bindViewHolder()方法绢掰,在復(fù)用時(shí)就是這里調(diào)用的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末童擎,一起剝皮案震驚了整個(gè)濱河市滴劲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌顾复,老刑警劉巖哑芹,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異捕透,居然都是意外死亡聪姿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門乙嘀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來末购,“玉大人,你說我怎么就攤上這事虎谢∶肆瘢” “怎么了?”我有些...
    開封第一講書人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵婴噩,是天一觀的道長擎场。 經(jīng)常有香客問我,道長几莽,這世上最難降的妖魔是什么迅办? 我笑而不...
    開封第一講書人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮章蚣,結(jié)果婚禮上站欺,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好矾策,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開白布磷账。 她就那樣靜靜地躺著,像睡著了一般贾虽。 火紅的嫁衣襯著肌膚如雪逃糟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評(píng)論 1 291
  • 那天蓬豁,我揣著相機(jī)與錄音绰咽,去河邊找鬼。 笑死庆尘,一個(gè)胖子當(dāng)著我的面吹牛剃诅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播驶忌,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼矛辕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了付魔?” 一聲冷哼從身側(cè)響起聊品,我...
    開封第一講書人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎几苍,沒想到半個(gè)月后翻屈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妻坝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年伸眶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刽宪。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厘贼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出圣拄,到底是詐尸還是另有隱情嘴秸,我是刑警寧澤,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布庇谆,位于F島的核電站岳掐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏饭耳。R本人自食惡果不足惜串述,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哥攘。 院中可真熱鬧剖煌,春花似錦材鹦、人聲如沸逝淹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栅葡。三九已至茉兰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間欣簇,已是汗流浹背规脸。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留熊咽,地道東北人莫鸭。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像被因,于是被迫代替她去往敵國和親衫仑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子文狱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

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