RecyclerView原始碼分析(一)--整體設計
扯淡的導語
好像自從RecyclerView這個控制元件一出現,對這個控制元件使用方法的文章就層出不窮。我是一隻都在使用這個控制元件,但是從來沒有過深入的研究它。對於這樣一個人人吹捧的控制元件,怎能不去研究一下。本想找找現成的分析原始碼的文章,結果並沒有如願。以前都是指望老羅,現在要親自動手了。我是一個堅持寫乾貨的人,這一段你就當沒看到。
RecyclerView這個控制元件出來已經有一段時間了,如果看這篇文章的你,還沒有使用過這個控制元件。那請先去學習怎樣使用。不然看也白看。這裡奉上一些關於介紹RecyclerView使用方法的優秀部落格:
- D_clock愛吃蔥花的 RecyclerView 和 ListView 使用對比分析
這幾篇文章都是介紹RecyclerView使用方法的精品文章,其次還有很多大神做的RecyclerView的第三方庫,這裡我就不一一列舉了,自己去按需搜尋吧。
然後對於已經對RecyclerView有初步瞭解的讀者,我們一起步入本文的正題。
RecyclerView的設計目的
研究一個現有的控制元件,先看看這個控制元件的設計目的是什麼。其實就是看看RecyclerView是幹什麼的。官方對RecyclerView的介紹是很簡短的一句話:
A flexible view for providing a limited window into a large data set.
一個用來為大量資料集合提供有限視窗的靈活的檢視。我的翻譯有點怪,自己看英文理解。介紹言簡意賅,一針見血...好,我沒詞兒了。
其中關鍵的有兩點:
- providing a limited window into a large data set
- flexible
針對與這兩點我們可以看看RecyclerView的整體設計。
RecyclerView整體設計
RecyclerView中,針對要達到的功能點,都有相關的設計,下面分點來分析RecyclerView的設計。
RecyclerView資料展示的設計思路
在上一節中提到的,其設計目的的第一點就是展示大量資料。其實RecyclerView在這一點上和ListView等控制元件具有相同的設計思路,都是使用了設計模式中的介面卡模式。不過即使你不知道介面卡模式也不用擔心。
首先呢,來看一張 巨醜無比 但是 簡單明瞭 的結構圖:
圖一
首先RecyclerView是一個ViewGroup,它和我們常用的各種Layout一樣,是用來裝很多子View的容器,那麼它裡面裝的那些View是怎麼來的呢?其實是來自ViewHolder中的itemView的。那麼ViewHolder是從哪裡生成的呢?顯示的資料又是在哪裡設定的呢?這就是Adapter的作用,它根據要展示資料的內容和型別,生成相應的ViewHolder,並對相應的View進行設定,從而展示出來。
如果從資料來源出發就是,Adapter將要展示的資料根據其內容和型別,轉化成對應的ViewHolder並對其進行設定,然後RecyclerView把ViewHolder中的itemView展示出來。
如果把這個圖套用到介面卡模式中,RecyclerView就是其中的Client,ViewHolder就是Target,Adapter自然就是Adapter,Data就是Adaptee。我這個圖沒有嚴格去按照介面卡模式中的畫是為了讓即使不知道介面卡模式的人也能看懂。
這個結構其實不通過原始碼也可以看出,在使用RecyclerView的時候也可以體會到。其中由Data生成對應用於展示的ViewHolder,就是通過實現Adapter
中的onCreateViewHolder(ViewGroup parent, int viewType);
和onBindViewHolder(VH holder, int position);
這兩個方法。
設計目的中的第一點我們清楚了,那麼我們來看第二點。
RecyclerView flexible的設計思路
在研究和探討這個問題的之前我們需要具體化flexible。那麼RecyclerView有哪些地方體現出了flexible?個人拙見有以下幾點:
- 佈局
- 動畫
- 裝飾
這些大家基本也都知道。那麼我們分別看它在每個功能點上面的設計:
RecyclerView佈局策略設計思路
細心的讀者應該在上圖中發現,在ViewHolder到RecyclerView的箭頭上有三個點,其實就是暗示了這其中還有很多的貓膩!
還是先上一張 巨醜無比 但 簡單明瞭 的圖。
圖二
RecyclerView佈局十分靈活,是因為RecyclerView將自己的佈局策略全權交給了LayoutManager。仔細閱讀原始碼還可以發現,就連View的新增,都是通過LayoutManager完成的。LayoutManager所做的事情就是拿到ViewHolder中的itemView,然後根據LayoutManager中定義的佈局策略,對itemView進行佈局,然後新增到RecyclerView中。
因此使用者可以根據自己的需要,自定義佈局策略,而這裡系統提供好了三種佈局策略,線性佈局,網格佈局和瀑布流佈局。一般情況下這三種已經滿足了我們的需求。如果不能,使用者可以自定義佈局策略。
RecyclerView動畫過程系統設計思路
RecyclerView作為一種展示大量資料的檢視控制元件,難免會遇到資料變化的情況。例如新增,刪除,更改等。當這些事情發生的時候,猿人往往喜歡通過動畫來體現這種變化。那麼在RecyclerView中便提供了一種非常靈活的動畫機制。
同樣先上一張 巨醜無比 但 簡單明瞭 的圖。
圖三
首先,達到資料改變觸發動畫,我們通常使用Adapter中的notifyXXX方法即可。但是其內部是如何工作的呢?
其實notify系列的方法可以看作是發出一個事件,在這裡Adapter和RecyclerView的工作原理,是一個典型的觀察者模式。
RecyclerView是觀察者,Adapter是可觀察的,在設定Adapter的時候RecyclerView訂閱觀察事件,當Adapter中的資料發生改變的時候通知RecyclerView。然後RecyclerView接到通知之後進行了很多處理。並觸發重新佈局。在佈局過程中又經過一系列處理,將這些動畫的資訊儲存到ViewInfoStore中。在佈局結束的時候由ViewInfoStore統一處理並通過CallBack中的方法呼叫ItemAnimator中的方法執行動畫。
RecyclerView動畫的靈活性是通過ItemAnimator實現的。各位猿們可以通過繼承ItemAnimator,然後實現裡面的方法,來實現各種各樣的動畫效果。
RecyclerView裝飾系統設計思路
這裡其實並沒有什麼好講的,實現ItemDecoration類中的抽象函式即可。RecyclerView內部就是在onDraw的時候執行ItemDecoration的onDraw,在draw的時候執行ItemDecoration的onDrawOver函式。在計算itemView的padding的時候將getItemOffsets得到的Rect加入其中,從而空出裝飾內容的區域。其靈活性在於程式設計師們可以自定義ItemDecoration,實現各種各樣的裝飾。
對於ItemDecoration有一篇文章介紹的比較好,在這裡推薦給大家。
RecyclerView檢視複用的設計思路
結合前兩節的內容,我們的結構圖應該成這個樣子了(動畫部分於該節無關,省略動畫部分結構圖):
圖四
其中ViewHolder的那一列很奇怪,是有多少個Data就有多少ViewHolder嗎?ViewHolder是儲存在哪裡的?
那麼將RecyclerView的複用結構補充上。又一張 巨醜無比 但 簡單明瞭 的圖。
圖五
這個相對於圖四多了一個Recycler和RecyclerViewPool。這兩個可能都不熟悉,那麼對這兩個類進行一個簡單的介紹:
Recycler
A Recycler is responsible for managing scrapped or detached item views for reuse.
一個Recycler是負責管理成為碎片的檢視或者已經detached的檢視,從而實現View的複用。
RecyclerViewPool
RecycledViewPool lets you share Views between multiple RecyclerViews.
RecycledViewPool可以讓你在多個RecyclerView之間分享檢視
翻譯的不好,不能忍的看原文。
介紹都說的很明白了,還有其實ViewHolder的建立和bind都是由Recycler執行的。還有LayoutManager獲得ViewHolder的itemView,也是通過Recycler提供的。簡單介紹一下Recycler和RecyclerViewPool的內部結構。
- Recycler裡有幾個ViewHolder的容器,用來儲存不同狀態的ViewHolder,以便之後複用。其中ViewCacheExtension類,是使用者可以自定義複用機制的類。
- RecyclerViewPool,這個可以從外部對多個RecyclerView設定同一個RecyclerViewPool,從而實現多個RecyclerView中的ViewHolder的複用。
總結
本章簡單的介紹了RecyclerView內部設計的大體框架結構。接下來會詳細的介紹主要流程和機制。整理原始碼很費體力,如果這篇文章讓你有所收穫,請不要吝惜你的喜歡,你的喜歡是我寫作的動力。
作者:柴澤建_Jack
連結:https://www.jianshu.com/p/9ddfdffee5d3
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。