RecyclerView的超強(qiáng)輔助Graywater——理論篇

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

  1. RecyclerView的超強(qiáng)輔助Graywater——理論篇
  2. RecyclerView的超強(qiáng)輔助Graywater——基礎(chǔ)實(shí)操篇
  3. RecyclerView的超強(qiáng)輔助Graywater——點(diǎn)擊事件
  4. RecyclerView的超強(qiáng)輔助Graywater——綜合實(shí)操篇

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

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

  • 問題一:Graywater是什么

  • 問題二:Graywater特點(diǎn)是什么?

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

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

一個(gè)問題一個(gè)問題的來看钾菊。

第一個(gè)問題:Graywater是什么?

Graywater是一個(gè)由Tumblr開發(fā)的第三方類庫偎肃,是RecyclerView的一個(gè)適配器(Adapter)煞烫。因?yàn)镚raywater的多模塊設(shè)計(jì)方式,所以在繼承GraywaterAdapter時(shí)累颂,需要同時(shí)實(shí)現(xiàn)Graywater中各個(gè)模塊的相關(guān)類滞详,來實(shí)現(xiàn)Graywater的特點(diǎn)。它最大的好處是能高效的處理復(fù)雜的列表紊馏,使復(fù)雜的列表使用起來如絲般順滑料饥。

看一下官方Demo的GIF圖:

Graywater1.gif

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

Graywater2.gif

第二個(gè)問題:Graywater有什么特點(diǎn)赫编?

通常我們?cè)谑褂肦ecyclerView.Adapter時(shí)巡蘸,是將數(shù)據(jù)集合(model)和對(duì)應(yīng)的ViewHolder相匹配奋隶,這種結(jié)構(gòu)用在存在大量樣式復(fù)雜的View時(shí)候,很容易變得卡頓悦荒。

下圖是一個(gè)普通的列表唯欣,為了提高體驗(yàn),超過屏幕部分的部分其實(shí)是可以回收的:

列表顯示.png

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

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

  • 一個(gè)Model能擁有不同的Viewholders萍聊,一個(gè)item對(duì)應(yīng)一個(gè)Model,所以一個(gè)item也就能擁有無數(shù)個(gè)body viewholders嘀趟。

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

第三個(gè)問題:Graywater原理是什么她按?

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

原理圖1.png

這張圖里面涉及到了5個(gè)類:

  • Model
  • ViewHolder
  • ViewHolderCreator
  • Binder
  • ItemBinder

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

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

同時(shí)羡宙,Graywater也不再追求單一的model與viewholder之間一對(duì)一的關(guān)系狸剃,因?yàn)閱我坏膍odel只能產(chǎn)生單一的視圖。而是將這兩者之間的關(guān)系變成了一對(duì)多的關(guān)系狗热,這樣Adapter的靈活度就大大提升钞馁,一個(gè)Item就可以有Head、Body和Footer(其中的ViewHolder可以任意添加匿刮,沒有限制)僧凰。

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

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

原理圖1.png

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

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

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

原理.png

圖中還剩一個(gè)ViewHolderCreator是干嘛的呢总珠?

在RecyclerView.Adapter的onCreateViewHolder()方法中需要?jiǎng)?chuàng)建ViewHolder屏鳍,這個(gè)時(shí)候ViewHolderCreator就派上用場(chǎng)了。

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

針對(duì)某一個(gè)類型的Item淫奔,創(chuàng)建對(duì)應(yīng)的5個(gè)基本類山涡,并建立相應(yīng)的關(guān)系,關(guān)系全部建立好之后唆迁,就可以開始分別實(shí)現(xiàn)鸭丛,得到一個(gè)高性能的Adapter。

第四個(gè)問題:與原有的RecyclerView.Adapter相比唐责,Graywater重寫了哪些核心方法鳞溉?

Graywater將常用的4個(gè)方法全都重寫了

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

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

onCreateViewHolder(ViewGroup parent, int viewType)

在RecyclerView.Adapter中,在 onCreateViewHolder(ViewGroup parent, int viewType)里我們需要返回一個(gè)ViewHolder對(duì)象朴恳。而在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);
    }

從源碼里看到于颖,有一個(gè)mViewHolderCreatorMap集合贞绵,這個(gè)集合中key值是ViewHolder的class類型Class<? extends VH>,value是ViewHolderCreator恍飘。從mViewHolderCreatorMap中獲取到ViewHolderCreator,再通過create()方法創(chuàng)建ViewHolder谴垫,當(dāng)然create()方法是由我們?cè)趯?shí)現(xiàn)ViewHolderCreator接口時(shí)來實(shí)現(xiàn)的章母。

也就是關(guān)系

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

onBindViewHolder(RecyclerView.ViewHolder holder, int position)

這是RecyclerView.Adapter最核心的方法,Graywater通過Binder在這個(gè)方法中翩剪,將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類中我們需要重寫一個(gè)bind()方法(有點(diǎn)類似onBindViewHolder,把數(shù)據(jù)給到view)前弯。從這里我們就看到蚪缀,bind()方法是怎么使用的了秫逝。

最核心的代碼:

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

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

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

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

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

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

P.S.
Graywater Github地址

如果對(duì)你有幫助的話,點(diǎn)贊护桦、評(píng)論含衔、贊賞都是對(duì)我的鼓勵(lì),也是支持我寫下去的動(dòng)力二庵,謝謝贪染!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市眨猎,隨后出現(xiàn)的幾起案子抑进,更是在濱河造成了極大的恐慌,老刑警劉巖睡陪,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寺渗,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡兰迫,警方通過查閱死者的電腦和手機(jī)信殊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汁果,“玉大人涡拘,你說我怎么就攤上這事【莸拢” “怎么了鳄乏?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)棘利。 經(jīng)常有香客問我橱野,道長(zhǎng),這世上最難降的妖魔是什么善玫? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任水援,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蜗元。我一直安慰自己或渤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布奕扣。 她就那樣靜靜地躺著薪鹦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪成畦。 梳的紋絲不亂的頭發(fā)上距芬,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音循帐,去河邊找鬼框仔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拄养,可吹牛的內(nèi)容都是我干的离斩。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼瘪匿,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼跛梗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起棋弥,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤核偿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后顽染,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漾岳,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年粉寞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尼荆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡唧垦,死狀恐怖捅儒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情振亮,我是刑警寧澤巧还,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站坊秸,受9級(jí)特大地震影響狞悲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜妇斤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧站超,春花似錦荸恕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至算撮,卻和暖如春生宛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肮柜。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工陷舅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人审洞。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓莱睁,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親芒澜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子仰剿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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