關(guān)于Graywater的系列文章
- RecyclerView的超強(qiáng)輔助Graywater——理論篇
- RecyclerView的超強(qiáng)輔助Graywater——基礎(chǔ)實(shí)操篇
- RecyclerView的超強(qiáng)輔助Graywater——點(diǎn)擊事件
- 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圖:
下面是我寫的一個(gè)Demo的GIF圖,我寫的這個(gè)Demo不是很復(fù)雜朱监,只是起到一個(gè)拋磚引玉的結(jié)果岸啡,Graywater還能實(shí)現(xiàn)更復(fù)雜的效果。
第二個(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í)是可以回收的:
為了將超過屏幕的部分給回收搬味,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ì)酌泰。
這張圖里面涉及到了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è)類熟丸。所以就有了最開始的原理圖:
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)系也就建立起來了,下圖可以更直觀的展示:
圖中還剩一個(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)力二庵,謝謝贪染!