RecyclerView的繪制以及緩存和復(fù)用機(jī)制分析

簡介

RecyclerView簡稱RV逆日,是ListView和GridView的加強(qiáng)版。

常規(guī)使用步驟

  • 設(shè)置布局管理器(必須的)

    RecyclerView.setLayoutManager()
    
  • 設(shè)置適配器(必須的)

    RecyclerView.setAdapter()
    
  • 設(shè)置Item的裝飾器(非必須的)

    RecyclerView.setItemAnimator()
    
  • 設(shè)置Item的動畫(非必須的)

    RecyclerView.addItemDecoration()
    

RecyclerView的繪制流程分析

按照 onMeasure() ---> onLayout() ---> onDraw()流程去分析

onMeasure()
  • RecyclerView的測量過程是委托給LayoutManager來完成
  • LayoutManager中的測量工作
    • 如果RecyclerView的寬和高都設(shè)置了match_parent或者具體數(shù)值辣之,那么就調(diào)用LayoutManager中的onMeasure()方法來進(jìn)行測量
    • 如果RecyclerView設(shè)置的是wrap_content,就會執(zhí)行RecyclerView中的dispatchLayoutStep2()方法來進(jìn)行測量
  • 其中RecyclerView中的dispatchLayoutStep1()方法是和RecyclerView中的Item動畫相關(guān)府蔗。
onLayout()
  • RecyclerView的布局過程是委托給LayoutManager來完成后的
  • onLayout方法中,核心方法是 dispatchLayout()
    • 在onMeasure方法中沒有調(diào)用dispatchLayoutStep2()去測量子View檩帐,會在此方法中調(diào)用去測量崖面。
  • disPatchLayoutStep2()方法的核心就是調(diào)用LayoutManager的onLayoutChildren()方法去測量子View的大小元咙,并確定子View的位置
    • 其中LayoutManager中的onLayoutChildren()方法是一個空方法,我們熟悉的LienarLayout巫员、GridLayoutManager庶香、StaggeredlayoutManager都對該方法進(jìn)行了重寫,有自己的實(shí)現(xiàn)方式简识。
  • 看下LinearLayout的onLayoutChildren()方法
    • 核心是fill()方法
    • 在fill()方法赶掖,通過while循環(huán)來判斷時候有過剩的空間來足夠繪制一個完整的子View
    • 其中l(wèi)ayoutChunk方法是子View測量布局的真正實(shí)現(xiàn)。
    • layoutChunk方法是一個非常核心的方法七扰。該方法執(zhí)行一次就將子View填充到RV中奢赂。
      • 其中會調(diào)用 layoutState.next()方法,獲取到一個View(實(shí)際是從緩存中查找ViewHolder或者創(chuàng)刊一個新的ViewHolder颈走,拿到ViewHolder綁定的View)
onDraw()

測量和布局的過程完畢膳灶,接下來就是繪制的操作

  • 很簡單,如果有添加ItemDecoration立由,那么就遍歷取出轧钓,然后進(jìn)行繪制操作

RecyclerView中的緩存復(fù)用原理Recycler

RV中的緩存復(fù)用主要體現(xiàn)在ViewHolder的緩存和復(fù)用

  • RV對ViewHolder的緩存和復(fù)用的核心代碼都是在RV的內(nèi)部類Recycler中完成的司致。
Recycelr的分級緩存
  • 一級緩存(mAttachedScrap和mChangeScrap)
    • 一級緩存主要是用來緩存屏幕中的ViewHolder
    • 場景
      • 第一次我們調(diào)用setLayoutManger和setAdapter之后,Rv會進(jìn)行一次layout并顯示到屏幕中聋迎,此時的ViewHolder是經(jīng)過onCreateViewHolder創(chuàng)建的。
      • 我們進(jìn)行下拉刷新請求到數(shù)據(jù)的時候枣耀,會調(diào)用notifyXX的方法霉晕,此時會將屏幕中的可見的ViewHolder緩存到Scarp中,當(dāng)緩存完之后捞奕,然后從Recycler的從緩存中根據(jù)postion獲取相應(yīng)的ViewHolder牺堰,之后將數(shù)據(jù)更新到相應(yīng)的ViewHolder中。最后再將這些ViewHolder繪制到屏幕上颅围。
  • 二級緩存(mCachedViews)
    • 主要用來緩存屏幕之外的ViewHolder伟葫,緩存的容量為2個。(這個容量是可以通過setViewCacheSize方法來改變的)
    • 當(dāng)緩存的容量已經(jīng)滿了院促,當(dāng)有新的ViewHolder要進(jìn)行緩存的話筏养,就根據(jù)FIFO規(guī)則將舊的ViewHolder從緩存中移除。
    • 注意:剛被移除屏幕之外的ViewHolder通常會立即被使用到常拓,所以被移除屏幕之外的ViewHolder不會被立即標(biāo)記為無效ViewHolder渐溶,而是將它緩存在cache中 (也就是mCachedViews中),但是又不能將所有移除屏幕之外的ViewHolder都視為非無效的弄抬。所以它的緩存大小為2茎辐。
    • 如果在二級緩存中沒有找到符合條件的ViewHolder,即使二級緩存中存在ViewHolder掂恕,LayoutManager也不會從二級緩存中取ViewHolder拖陆,而是到四級緩存中取出一個ViewHolder,然后在onBindViewHolder中給ViewHolder重新設(shè)置數(shù)據(jù)懊亡。
  • 三級緩存(ViewCacheExtension)
    • 這是RV預(yù)留給我們開發(fā)人員的一個抽象類依啰,我們可以繼承這個抽象類,復(fù)寫抽象方法斋配,來自定義自己的緩存機(jī)制孔飒。
  • 四級緩存(RecycledViewPool)
    • 也是用來緩存屏幕之外的ViewHodler,主要是用來緩存從二級緩存中淘汰的ViewHolder
      • 當(dāng)ViewHolder緩存到RecycledViewPool中的時候艰争,會將數(shù)據(jù)從ViewHodler中清空坏瞄,當(dāng)再次使用時候會調(diào)用onBindView重新設(shè)置數(shù)據(jù)
    • 多個RV可以共享一個RecycledViewPool。

RV從緩存中取出ViewHolder

  • 在 onlayout過程中甩卓,layoutChunk方法通過layoutState.next方法拿到某一個子View鸠匀,然后添加到RV中
  • 在layoutState.next()方法中,通過getViewForPosition()方法獲取到View
  • getViewForPosition()方法調(diào)用了tryGetViewHolderforPositionByDealine()方法
  • 在tryGetViewHolderforPositionByDealine()方法中會依次調(diào)用這4幾緩存查找相應(yīng)位置的ViewHolder
  • 在緩存中都沒有找到逾柿,就調(diào)用onCreateViewHolder()方法創(chuàng)建一個新的ViewHolder
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缀棍,一起剝皮案震驚了整個濱河市宅此,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌爬范,老刑警劉巖父腕,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異青瀑,居然都是意外死亡璧亮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門斥难,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枝嘶,“玉大人,你說我怎么就攤上這事哑诊∪悍觯” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵镀裤,是天一觀的道長竞阐。 經(jīng)常有香客問我,道長淹禾,這世上最難降的妖魔是什么馁菜? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮铃岔,結(jié)果婚禮上汪疮,老公的妹妹穿的比我還像新娘。我一直安慰自己毁习,他們只是感情好智嚷,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纺且,像睡著了一般盏道。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上载碌,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天猜嘱,我揣著相機(jī)與錄音,去河邊找鬼嫁艇。 笑死朗伶,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的步咪。 我是一名探鬼主播论皆,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了点晴?” 一聲冷哼從身側(cè)響起感凤,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎粒督,沒想到半個月后陪竿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屠橄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年萨惑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仇矾。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖解总,靈堂內(nèi)的尸體忽然破棺而出贮匕,到底是詐尸還是另有隱情,我是刑警寧澤花枫,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布刻盐,位于F島的核電站,受9級特大地震影響劳翰,放射性物質(zhì)發(fā)生泄漏敦锌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一佳簸、第九天 我趴在偏房一處隱蔽的房頂上張望乙墙。 院中可真熱鬧,春花似錦生均、人聲如沸听想。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汉买。三九已至,卻和暖如春佩脊,著一層夾襖步出監(jiān)牢的瞬間蛙粘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工威彰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留出牧,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓抱冷,卻偏偏與公主長得像崔列,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355