Android ListView與RecyclerView對(duì)比淺析--緩存機(jī)制

一,背景
RecyclerView是谷歌官方出的一個(gè)用于大量數(shù)據(jù)展示的新控件侄非,可以用來代替?zhèn)鹘y(tǒng)的ListView蕉汪,更加強(qiáng)大和靈活。
最近逞怨,自己負(fù)責(zé)的業(yè)務(wù)者疤,也遇到這樣的一個(gè)問題,關(guān)于是否要將ListView替換為RecyclerView叠赦?
秉承著實(shí)事求是的作風(fēng)驹马,弄清楚RecyclerView是否有足夠的吸引力替換掉ListView,我從性能這一角度出發(fā)除秀,研究RecyclerView和ListView二者的緩存機(jī)制糯累,并得到了一些較有益的”結(jié)論”,待我慢慢道來鳞仙。
同時(shí)也希望能通過本文寇蚊,讓大家快速了解RecyclerView與ListView在緩存機(jī)制上的一些區(qū)別,在使用上也更加得心應(yīng)手吧棍好。
PS:相關(guān)知識(shí): ListView與RecyclerView緩存機(jī)制原理大致相似仗岸,如下圖所示:



過程中,離屏的ItemView即被回收至緩存借笙,入屏的ItemView則會(huì)優(yōu)先從緩存中獲取扒怖,只是ListView與RecyclerView的實(shí)現(xiàn)細(xì)節(jié)有差異.(這只是緩存使用的其中一個(gè)場景,還有如刷新等)
PPS:本文不貼出詳細(xì)代碼业稼,結(jié)合源碼食用更佳盗痒!
二. 正文
2.1 緩存機(jī)制對(duì)比

  1. 層級(jí)不同:
    RecyclerView比ListView多兩級(jí)緩存,支持多個(gè)離ItemView緩存低散,支持開發(fā)者自定義緩存處理邏輯俯邓,支持所有RecyclerView共用同一個(gè)RecyclerViewPool(緩存池)。
    具體來說: ListView(兩級(jí)緩存):



    RecyclerView(四級(jí)緩存):



    ListView和RecyclerView緩存機(jī)制基本一致:
    1). mActiveViews和mAttachedScrap功能相似熔号,意義在于快速重用屏幕上可見的列表項(xiàng)ItemView稽鞭,而不需要重新createView和bindView;
    2). mScrapView和mCachedViews + mReyclerViewPool功能相似引镊,意義在于緩存離開屏幕的ItemView朦蕴,目的是讓即將進(jìn)入屏幕的ItemView重用.
    3). RecyclerView的優(yōu)勢在于a.mCacheViews的使用,可以做到屏幕外的列表項(xiàng)ItemView進(jìn)入屏幕內(nèi)時(shí)也無須bindView快速重用弟头;b.mRecyclerPool可以供多個(gè)RecyclerView共同使用吩抓,在特定場景下,如viewpaper+多個(gè)列表頁下有優(yōu)勢.客觀來說赴恨,RecyclerView在特定場景下對(duì)ListView的緩存機(jī)制做了補(bǔ)強(qiáng)和完善疹娶。
  2. 緩存不同:
    1). RecyclerView緩存RecyclerView.ViewHolder,抽象可理解為: View + ViewHolder(避免每次createView時(shí)調(diào)用findViewById) + flag(標(biāo)識(shí)狀態(tài))伦连; 2). ListView緩存View雨饺。
    緩存不同挣饥,二者在緩存的使用上也略有差別,具體來說: ListView獲取緩存的流程:



    RecyclerView獲取緩存的流程:



    1). RecyclerView中mCacheViews(屏幕外)獲取緩存時(shí)沛膳,是通過匹配pos獲取目標(biāo)位置的緩存扔枫,這樣做的好處是,當(dāng)數(shù)據(jù)源數(shù)據(jù)不變的情況下锹安,無須重新bindView:

    而同樣是離屏緩存短荐,ListView從mScrapViews根據(jù)pos獲取相應(yīng)的緩存,但是并沒有直接使用叹哭,而是重新getView(即必定會(huì)重新bindView)忍宋,相關(guān)代碼如下:
//AbsListView源碼:line2345
//通過匹配pos從mScrapView中獲取緩存
final View scrapView = mRecycler.getScrapView(position);
//無論是否成功都直接調(diào)用getView,導(dǎo)致必定會(huì)調(diào)用createView
final View child = mAdapter.getView(position, scrapView, this);
if (scrapView != null) {
    if (child != scrapView) {
        mRecycler.addScrapView(scrapView, position);
    } else {
        ...
    }
}

2). ListView中通過pos獲取的是view,即pos–>view风罩; RecyclerView中通過pos獲取的是viewholder糠排,即pos –> (view,viewHolder超升,flag)入宦; 從流程圖中可以看出,標(biāo)志flag的作用是判斷view是否需要重新bindView室琢,這也是RecyclerView實(shí)現(xiàn)局部刷新的一個(gè)核心.
2.2 局部刷新
由上文可知乾闰,RecyclerView的緩存機(jī)制確實(shí)更加完善,但還不算質(zhì)的變化盈滴,RecyclerView更大的亮點(diǎn)在于提供了局部刷新的接口涯肩,通過局部刷新,就能避免調(diào)用許多無用的bindView.



(RecyclerView和ListView添加巢钓,移除Item效果對(duì)比)
結(jié)合RecyclerView的緩存機(jī)制病苗,看看局部刷新是如何實(shí)現(xiàn)的: 以RecyclerView中notifyItemRemoved(1)為例,最終會(huì)調(diào)用requestLayout()症汹,使整個(gè)RecyclerView重新繪制硫朦,過程為: onMeasure()–>onLayout()–>onDraw()
其中,onLayout()為重點(diǎn)烈菌,分為三步: 1. dispathLayoutStep1():記錄RecyclerView刷新前列表項(xiàng)ItemView的各種信息阵幸,如Top,Left,Bottom,Right花履,用于動(dòng)畫的相關(guān)計(jì)算芽世; 2. dispathLayoutStep2():真正測量布局大小,位置诡壁,核心函數(shù)為layoutChildren()济瓢; 3. dispathLayoutStep3():計(jì)算布局前后各個(gè)ItemView的狀態(tài),如Remove妹卿,Add旺矾,Move蔑鹦,Update等,如有必要執(zhí)行相應(yīng)的動(dòng)畫.
其中箕宙,layoutChildren()流程圖:




當(dāng)調(diào)用notifyItemRemoved時(shí)嚎朽,會(huì)對(duì)屏幕內(nèi)ItemView做預(yù)處理,修改ItemView相應(yīng)的pos以及flag(流程圖中紅色部分):

當(dāng)調(diào)用fill()中RecyclerView.getViewForPosition(pos)時(shí)柬帕,RecyclerView通過對(duì)pos和flag的預(yù)處理哟忍,使得bindview只調(diào)用一次.

需要指出,ListView和RecyclerView最大的區(qū)別在于數(shù)據(jù)源改變時(shí)的緩存的處理邏輯陷寝,ListView是”一鍋端”锅很,將所有的mActiveViews都移入了二級(jí)緩存mScrapViews,而RecyclerView則是更加靈活地對(duì)每個(gè)View修改標(biāo)志位凤跑,區(qū)分是否重新bindView爆安。
三.結(jié)論
在一些場景下,如界面初始化仔引,滑動(dòng)等扔仓,ListView和RecyclerView都能很好地工作,兩者并沒有很大的差異:

文章的開頭便拋出了這樣一個(gè)問題咖耘,微信Android客戶端卡券模塊当辐,大部分UI都是以列表頁的形式展示,實(shí)現(xiàn)方式為ListView鲤看,是否有必要將其替換成RecyclerView呢缘揪?


答案是否定的,從性能上看义桂,RecyclerView并沒有帶來顯著的提升找筝,不需要頻繁更新,暫不支持用動(dòng)畫慷吊,意味著RecyclerView優(yōu)勢也不太明顯袖裕,沒有太大的吸引力,ListView已經(jīng)能很好地滿足業(yè)務(wù)需求溉瓶。
數(shù)據(jù)源頻繁更新的場景急鳄,如彈幕:http://www.reibang.com/p/2232a63442d6等RecyclerView的優(yōu)勢會(huì)非常明顯;

進(jìn)一步來講堰酿,結(jié)論是: 列表頁展示界面疾宏,需要支持動(dòng)畫,或者頻繁更新触创,局部刷新坎藐,建議使用RecyclerView,更加強(qiáng)大完善,易擴(kuò)展岩馍;其它情況(如微信卡包列表頁)兩者都OK碉咆,但ListView在使用上會(huì)更加方便,快捷蛀恩。
Ps:僅從一個(gè)角度做了對(duì)比疫铜,盲人摸象,有誤跪求指正双谆。
四.參考資料

  1. ListView
    a. android-23源碼 b. Android ListView工作原理解析块攒,帶你從源碼的角度徹底理解:http://blog.csdn.net/guolin_blog/article/details/44996879 c. android自己動(dòng)手寫ListView學(xué)習(xí)其原理:http://blog.csdn.net/androiddevelop/article/details/8734255
  2. RecyclerView
    a. RecyclerView-v7-23.4.0源碼 b. RecyclerView剖析:http://blog.csdn.net/qq_23012315/article/details/50807224 c. RecyclerView剖析:http://blog.csdn.net/qq_23012315/article/details/51096696
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市佃乘,隨后出現(xiàn)的幾起案子囱井,更是在濱河造成了極大的恐慌,老刑警劉巖趣避,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庞呕,死亡現(xiàn)場離奇詭異,居然都是意外死亡程帕,警方通過查閱死者的電腦和手機(jī)住练,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愁拭,“玉大人讲逛,你說我怎么就攤上這事×氩海” “怎么了盏混?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長惜论。 經(jīng)常有香客問我许赃,道長,這世上最難降的妖魔是什么馆类? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任混聊,我火速辦了婚禮,結(jié)果婚禮上乾巧,老公的妹妹穿的比我還像新娘句喜。我一直安慰自己,他們只是感情好沟于,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布咳胃。 她就那樣靜靜地躺著,像睡著了一般社裆。 火紅的嫁衣襯著肌膚如雪拙绊。 梳的紋絲不亂的頭發(fā)上向图,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天泳秀,我揣著相機(jī)與錄音标沪,去河邊找鬼。 笑死嗜傅,一個(gè)胖子當(dāng)著我的面吹牛金句,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播吕嘀,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼违寞,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了偶房?” 一聲冷哼從身側(cè)響起趁曼,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎棕洋,沒想到半個(gè)月后挡闰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掰盘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年摄悯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愧捕。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奢驯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出次绘,到底是詐尸還是另有隱情瘪阁,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布邮偎,位于F島的核電站罗洗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏钢猛。R本人自食惡果不足惜伙菜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望命迈。 院中可真熱鬧贩绕,春花似錦、人聲如沸壶愤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽征椒。三九已至娇哆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碍讨。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國打工治力, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人勃黍。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓宵统,卻偏偏與公主長得像,于是被迫代替她去往敵國和親覆获。 傳聞我的和親對(duì)象是個(gè)殘疾皇子马澈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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