RecyclerView的超強輔助Graywater——理論篇

關(guān)于Graywater的系列文章

  1. RecyclerView的超強輔助Graywater——理論篇
  2. RecyclerView的超強輔助Graywater——基礎(chǔ)實操篇
  3. RecyclerView的超強輔助Graywater——點擊事件
  4. RecyclerView的超強輔助Graywater——綜合實操篇

Graywater是一個什么東西呢?它是由Tumblr開源的一個代替RecyclerView.Adapter的類庫。Graywater將RecyclerView.Adapter拆解并重新設(shè)計封裝后,能使復(fù)雜多重結(jié)構(gòu)的RecyclerView在使用時如絲般順滑。

我將從四個問題來帶大家了解什么是Graywater。

  • 問題一:Graywater是什么

  • 問題二:Graywater特點是什么?

  • 問題三:Graywater原理是什么?

  • 問題四:與原有的RecyclerView.Adapter相比,Graywater重寫了哪些核心方法?

一個問題一個問題的來看。

第一個問題:Graywater是什么?

Graywater是一個由Tumblr開發(fā)的第三方類庫,是RecyclerView的一個適配器(Adapter)。因為Graywater的多模塊設(shè)計方式,所以在繼承GraywaterAdapter時,需要同時實現(xiàn)Graywater中各個模塊的相關(guān)類,來實現(xiàn)Graywater的特點。它最大的好處是能高效的處理復(fù)雜的列表,使復(fù)雜的列表使用起來如絲般順滑。

看一下官方Demo的GIF圖:

Graywater1.gif

下面是我寫的一個Demo的GIF圖,我寫的這個Demo不是很復(fù)雜,只是起到一個拋磚引玉的結(jié)果,Graywater還能實現(xiàn)更復(fù)雜的效果。

Graywater2.gif

第二個問題:Graywater有什么特點?

通常我們在使用RecyclerView.Adapter時,是將數(shù)據(jù)集合(model)和對應(yīng)的ViewHolder相匹配,這種結(jié)構(gòu)用在存在大量樣式復(fù)雜的View時候,很容易變得卡頓。

下圖是一個普通的列表,為了提高體驗,超過屏幕部分的部分其實是可以回收的:

列表顯示.png

為了將超過屏幕的部分給回收,Tumblr采用了以下2個設(shè)計來提高性能并減少內(nèi)存。

  • Viewholders能夠被相同或者不同類型的models所共享,上圖中item#1和item#2的body viewholder就可以被共享。

  • 一個Model能擁有不同的Viewholders,一個item對應(yīng)一個Model,所以一個item也就能擁有無數(shù)個body viewholders。

這樣做的結(jié)果是能使用最少數(shù)量的ViewHolders來最大化內(nèi)存的使用率,同時還能減少內(nèi)存的使用。

第三個問題:Graywater原理是什么?

在討論這個問題前,我們先眼熟一下這張圖,這張圖概括了Graywater的設(shè)計。

原理圖1.png

這張圖里面涉及到了5個類:

  • Model
  • ViewHolder
  • ViewHolderCreator
  • Binder
  • ItemBinder

Model和ViewHolder是在使用RecyclerView時本來就會用到的,但是這2個類,因為Graywater的設(shè)計原因,會跟在RecyclerView.Adapter使用時有一些區(qū)別。在下一篇基礎(chǔ)實操篇中可以看到。同時為了實現(xiàn)問題2中的2個特點,Tumblr在這兩者間添加了Binder類。來把model(T)數(shù)據(jù)綁定到 viewholder (VH)視圖上。

+-------+     +--------+     +------------+
| Model | --> | Binder | --> | ViewHolder |
+-------+     +--------+     +------------+

同時,Graywater也不再追求單一的model與viewholder之間一對一的關(guān)系,因為單一的model只能產(chǎn)生單一的視圖。而是將這兩者之間的關(guān)系變成了一對多的關(guān)系,這樣Adapter的靈活度就大大提升,一個Item就可以有Head、Body和Footer(其中的ViewHolder可以任意添加,沒有限制)。

                           +--------+     +------------+
                      /--> | Binder | --> | ViewHolder |
+-------+     +---+  /     +--------+     +------------+
| Model | --> | ? | *----> | Binder | --> | ViewHolder |
+-------+     +---+  \     +--------+     +------------+
                      \--> | Binder | --> | ViewHolder |
                           +--------+     +------------+

為了管理這種一對多關(guān)系,所以又添加Itembinder這一個類。所以就有了最開始的原理圖:

原理圖1.png

ItemBinder用來管理一個Item中所有的Binder類,有一個getBinderList()方法來返回所管理的binder集合。同時在實現(xiàn)ItemBinder接口時,需要傳入Model的類型,ItemBinder需要知道它所對應(yīng)的的數(shù)據(jù)類型(Model)是什么。

Binder<? super T, ? extends VH>接口中會傳入Model和ViewHolder的類型。Binder類就將model和ViewHolder聯(lián)系了起來。

所以一環(huán)扣一環(huán),各個類的關(guān)系也就建立起來了,下圖可以更直觀的展示:

原理.png

圖中還剩一個ViewHolderCreator是干嘛的呢?

在RecyclerView.Adapter的onCreateViewHolder()方法中需要創(chuàng)建ViewHolder,這個時候ViewHolderCreator就派上用場了。

ViewHolderCreator是一種獨立于model來創(chuàng)建viewholder的方式(在模型和視圖之間具有一對一關(guān)系的其他庫中,此代碼將存在于模型中 ,例如Epoxy)。

針對某一個類型的Item,創(chuàng)建對應(yīng)的5個基本類,并建立相應(yīng)的關(guān)系,關(guān)系全部建立好之后,就可以開始分別實現(xiàn),得到一個高性能的Adapter。

第四個問題:與原有的RecyclerView.Adapter相比,Graywater重寫了哪些核心方法?

Graywater將常用的4個方法全都重寫了

  • getItemCount()
  • getItemViewType(int position)
  • onCreateViewHolder(ViewGroup parent, int viewType)
  • onBindViewHolder(RecyclerView.ViewHolder holder, int position)

前兩個方法我就不講了,大家可以自己去看Graywater的源碼Github地址,主要說說后面兩個。

onCreateViewHolder(ViewGroup parent, int viewType)

在RecyclerView.Adapter中,在 onCreateViewHolder(ViewGroup parent, int viewType)里我們需要返回一個ViewHolder對象。而在Graywater中,這件事就由ViewHolerCreator代勞了。

GraywaterAdapter onCreateViewHolder(ViewGroup parent, int viewType)的源碼:

    @Override
    public VH onCreateViewHolder(final ViewGroup parent, final int viewType) {
        return (VH) mViewHolderCreatorMap.get(getViewHolderClass(viewType)).create(parent);
    }

從源碼里看到,有一個mViewHolderCreatorMap集合,這個集合中key值是ViewHolder的class類型Class<? extends VH>,value是ViewHolderCreator。從mViewHolderCreatorMap中獲取到ViewHolderCreator,再通過create()方法創(chuàng)建ViewHolder,當然create()方法是由我們在實現(xiàn)ViewHolderCreator接口時來實現(xiàn)的。

也就是關(guān)系

+------------+     +-------------------+
| ViewHolder | <-- | ViewHolderCreator |
+------------+     +-------------------+

onBindViewHolder(RecyclerView.ViewHolder holder, int position)

這是RecyclerView.Adapter最核心的方法,Graywater通過Binder在這個方法中,將Model數(shù)據(jù)和ViewHolder視圖綁定起來。

    @Override
    @SuppressLint("RecyclerView")
    public void onBindViewHolder(final VH holder, final int viewHolderPosition) {

        final BinderResult result = computeItemAndBinderIndex(viewHolderPosition);
        final Binder binder = result.getBinder();

        if (binder != null && result.item != null) {

            if (mPreviousBoundViewHolderPosition == NO_PREVIOUS_BOUND_VIEWHOLDER) {
                prepare(viewHolderPosition, binder, result.item, result.binderList, result.binderIndex);
            }

            final ActionListener actionListener = mActionListenerMap.get(getModelType(result.item));

            binder.bind(result.item, holder, result.binderList, result.binderIndex, actionListener);

            prepareInternal(viewHolderPosition);
            mPreviousBoundViewHolderPosition = viewHolderPosition;
        }
    }

在Binder類中我們需要重寫一個bind()方法(有點類似onBindViewHolder,把數(shù)據(jù)給到view)。從這里我們就看到,bind()方法是怎么使用的了。

最核心的代碼:

 binder.bind(result.item, holder, result.binderList, result.binderIndex, actionListener);

BinderResult是GraywaterAdapter中的一個內(nèi)部類,擁有著與ViewHolder相關(guān)的Model、Binder的引用。

在binder和model不為空的情況下,將

  • model(result.item)
  • holder
  • binder集合(result.binderList)
  • 當前viewholder的位置(result.binderIndex)
  • actionListener

作為參數(shù)傳遞到我們重寫的bind()方法中,在bind方法中將數(shù)據(jù)model映射到view視圖上,RecyclerView就能顯示出數(shù)據(jù)了。

理論部分差不多就講完了,下一篇就是實戰(zhàn)了。

P.S.
Graywater Github地址

如果對你有幫助的話,點贊、評論、贊賞都是對我的鼓勵,也是支持我寫下去的動力,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容