ListView與RecyclerView緩存機制原理大緻相似,滑動過程中,離屏的ItemView即被回收至緩存,入屏的ItemView則會優先從緩存中擷取,隻是ListView與RecyclerView的實作細節有差異。(這隻是緩存使用的其中一個場景,還有如重新整理等)
一、緩存機制對比
1. 層級不同:
RecyclerView比ListView多兩級緩存,支援多個離ItemView緩存,支援開發者自定義緩存處理邏輯,支援所有RecyclerView共用同一個RecyclerViewPool(緩存池)。
具體來說:
ListView(兩級緩存):

RecyclerView(四級緩存):
ListView和RecyclerView緩存機制基本一緻:
1). mActiveViews和mAttachedScrap功能相似,意義在于快速重用螢幕上可見的清單項ItemView,而不需要重新createView和bindView;
2). mScrapView和mCachedViews + mReyclerViewPool功能相似,意義在于緩存離開螢幕的ItemView,目的是讓即将進入螢幕的ItemView重用.
3). RecyclerView的優勢在于a.mCacheViews的使用,可以做到螢幕外的清單項ItemView進入螢幕内時也無須bindView快速重用;b.mRecyclerPool可以供多個RecyclerView共同使用,在特定場景下,如viewpaper+多個清單頁下有優勢.客觀來說,RecyclerView在特定場景下對ListView的緩存機制做了補強和完善。
2. 緩存不同:
1). RecyclerView緩存RecyclerView.ViewHolder,抽象可了解為:
View + ViewHolder(避免每次createView時調用findViewById) + flag(辨別狀态);
2). ListView緩存View。
緩存不同,二者在緩存的使用上也略有差别,具體來說:
ListView擷取緩存的流程:
RecyclerView擷取緩存的流程:
1). RecyclerView中mCacheViews(螢幕外)擷取緩存時,是通過比對pos擷取目标位置的緩存,這樣做的好處是,當資料源資料不變的情況下,無須重新bindView;而同樣是離屏緩存,ListView從mScrapViews根據pos擷取相應的緩存,但是并沒有直接使用,而是重新getView(即必定會重新bindView)
2). ListView中通過pos擷取的是view,即pos-->view;
RecyclerView中通過pos擷取的是viewholder,即pos --> (view,viewHolder,flag);
從流程圖中可以看出,标志flag的作用是判斷view是否需要重新bindView,這也是RecyclerView實作局部重新整理的一個核心。
局部重新整理
由上文可知,RecyclerView的緩存機制确實更加完善,但還不算質的變化,RecyclerView更大的亮點在于提供了局部重新整理的接口,通過局部重新整理,就能避免調用許多無用的bindView。
(RecyclerView和ListView添加,移除Item效果對比)
結合RecyclerView的緩存機制,看看局部重新整理是如何實作的:
以RecyclerView中notifyItemRemoved(1)為例,最終會調用requestLayout(),使整個RecyclerView重新繪制,過程為:
onMeasure()-->onLayout()-->onDraw()
其中,onLayout()為重點,分為三步:
dispathLayoutStep1():記錄RecyclerView重新整理前清單項ItemView的各種資訊,如Top,Left,Bottom,Right,用于動畫的相關計算;
dispathLayoutStep2():真正測量布局大小,位置,核心函數為layoutChildren();
dispathLayoutStep3():計算布局前後各個ItemView的狀态,如Remove,Add,Move,Update等,如有必要執行相應的動畫.
其中,layoutChildren()流程圖:
當調用notifyItemRemoved時,會對螢幕内ItemView做預處理,修改ItemView相應的pos以及flag(流程圖中紅色部分):
當調用fill()中RecyclerView.getViewForPosition(pos)時,RecyclerView通過對pos和flag的預處理,使得bindview隻調用一次.
需要指出,ListView和RecyclerView最大的差別在于資料源改變時的緩存的處理邏輯,ListView是"一鍋端",将所有的mActiveViews都移入了二級緩存mScrapViews,而RecyclerView則是更加靈活地對每個View修改标志位,區分是否重新bindView。
二、結論
1、在一些場景下,如界面初始化,滑動等,ListView和RecyclerView都能很好地工作,兩者并沒有很大的差異:
文章的開頭便抛出了這樣一個問題,微信Android用戶端卡券子產品,大部分UI都是以清單頁的形式展示,實作方式為ListView,是否有必要将其替換成RecyclerView呢?
答案是否定的,從性能上看,RecyclerView并沒有帶來顯著的提升,不需要頻繁更新,暫不支援用動畫,意味着RecyclerView優勢也不太明顯,沒有太大的吸引力,ListView已經能很好地滿足業務需求。
2、資料源頻繁更新的場景,如彈幕等RecyclerView的優勢會非常明顯;
進一步來講,結論是:
清單頁展示界面,需要支援動畫,或者頻繁更新,局部重新整理,建議使用RecyclerView,更加強大完善,易擴充;其它情況(如微信卡包清單頁)兩者都OK,但ListView在使用上會更加友善,快捷。