天天看點

RecyclerView源碼分析(一)--整體設計RecyclerView的設計目的RecyclerView整體設計總結

扯淡的導語

好像自從RecyclerView這個控件一出現,對這個控件使用方法的文章就層出不窮。我是一隻都在使用這個控件,但是從來沒有過深入的研究它。對于這樣一個人人吹捧的控件,怎能不去研究一下。本想找找現成的分析源碼的文章,結果并沒有如願。以前都是指望老羅,現在要親自動手了。我是一個堅持寫幹貨的人,這一段你就當沒看到。

RecyclerView這個控件出來已經有一段時間了,如果看這篇文章的你,還沒有使用過這個控件。那請先去學習怎樣使用。不然看也白看。這裡奉上一些關于介紹RecyclerView使用方法的優秀部落格:

  • 鴻洋大神的 Android RecyclerView 使用完全解析 體驗藝術般的控件這篇文章詳細介紹了RecyclerView的基本使用方法,沒有用過的照着敲一遍應該就算是入門了。
  • 鴻洋大神的 為RecyclerView打造通用Adapter 讓RecyclerView更加好用這篇是鴻洋大神對RecyclerView的封裝,建議使用熟練了再來使用這個,不然很容易忘記原本的代碼應該怎樣寫。
  • D_clock愛吃蔥花的 RecyclerView 和 ListView 使用對比分析這個文章其實是一個RecyclerView的總結。隻不過是通過與ListView對比來的,對于熟悉ListView的Coder入手RecyclerView比較容易接受,但裡面對于RecyclerView的使用總結的很全面。

這幾篇文章都是介紹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源碼分析(一)--整體設計RecyclerView的設計目的RecyclerView整體設計總結

圖一

首先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?個人拙見有以下幾點:

  1. 布局
  2. 動畫
  3. 裝飾

這些大家基本也都知道。那麼我們分别看它在每個功能點上面的設計:

RecyclerView布局政策設計思路

細心的讀者應該在上圖中發現,在ViewHolder到RecyclerView的箭頭上有三個點,其實就是暗示了這其中還有很多的存在某種問題或陰謀!

還是先上一張 巨醜無比 但 簡單明了 的圖。

RecyclerView源碼分析(一)--整體設計RecyclerView的設計目的RecyclerView整體設計總結

圖二

RecyclerView布局十分靈活,是因為RecyclerView将自己的布局政策全權交給了LayoutManager。仔細閱讀源碼還可以發現,就連View的添加,都是通過LayoutManager完成的。LayoutManager所做的事情就是拿到ViewHolder中的itemView,然後根據LayoutManager中定義的布局政策,對itemView進行布局,然後添加到RecyclerView中。

是以使用者可以根據自己的需要,自定義布局政策,而這裡系統提供好了三種布局政策,線性布局,網格布局和瀑布流布局。一般情況下這三種已經滿足了我們的需求。如果不能,使用者可以自定義布局政策。

RecyclerView動畫過程系統設計思路

RecyclerView作為一種展示大量資料的視圖控件,難免會遇到資料變化的情況。例如添加,删除,更改等。當這些事情發生的時候,猿人往往喜歡通過動畫來展現這種變化。那麼在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 系列之一:ItemDecoration其中也進行了深入講解,而且我覺的可以了,這部分源碼也沒多少,很簡單。

RecyclerView視圖複用的設計思路

結合前兩節的内容,我們的結構圖應該成這個樣子了(動畫部分于該節無關,省略動畫部分結構圖):

RecyclerView源碼分析(一)--整體設計RecyclerView的設計目的RecyclerView整體設計總結

圖四

其中ViewHolder的那一列很奇怪,是有多少個Data就有多少ViewHolder嗎?ViewHolder是存儲在哪裡的?

那麼将RecyclerView的複用結構補充上。又一張 巨醜無比 但 簡單明了 的圖。

RecyclerView源碼分析(一)--整體設計RecyclerView的設計目的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的内部結構。

  1. Recycler裡有幾個ViewHolder的容器,用來存儲不同狀态的ViewHolder,以便之後複用。其中ViewCacheExtension類,是使用者可以自定義複用機制的類。
  2. RecyclerViewPool,這個可以從外部對多個RecyclerView設定同一個RecyclerViewPool,進而實作多個RecyclerView中的ViewHolder的複用。

總結

本章簡單的介紹了RecyclerView内部設計的大體架構結構。接下來會詳細的介紹主要流程和機制。整理源碼很費體力,如果這篇文章讓你有所收獲,請不要吝惜你的喜歡,你的喜歡是我寫作的動力。