关于Graywater的系列文章
- RecyclerView的超强辅助Graywater——理论篇
- RecyclerView的超强辅助Graywater——基础实操篇
- RecyclerView的超强辅助Graywater——点击事件
- RecyclerView的超强辅助Graywater——综合实操篇
Graywater是一个什么东西呢?它是由Tumblr开源的一个代替RecyclerView.Adapter的类库。Graywater将RecyclerView.Adapter拆解并重新设计封装后,能使复杂多重结构的RecyclerView在使用时如丝般顺滑。
我将从四个问题来带大家了解什么是Graywater。
问题一:Graywater是什么
问题二:Graywater特点是什么?
问题三:Graywater原理是什么?
问题四:与原有的RecyclerView.Adapter相比,Graywater重写了哪些核心方法?
一个问题一个问题的来看。
第一个问题:Graywater是什么?
Graywater是一个由Tumblr开发的第三方类库,是RecyclerView的一个适配器(Adapter)。因为Graywater的多模块设计方式,所以在继承GraywaterAdapter时,需要同时实现Graywater中各个模块的相关类,来实现Graywater的特点。它最大的好处是能高效的处理复杂的列表,使复杂的列表使用起来如丝般顺滑。
看一下官方Demo的GIF图:
下面是我写的一个Demo的GIF图,我写的这个Demo不是很复杂,只是起到一个抛砖引玉的结果,Graywater还能实现更复杂的效果。
第二个问题:Graywater有什么特点?
通常我们在使用RecyclerView.Adapter时,是将数据集合(model)和对应的ViewHolder相匹配,这种结构用在存在大量样式复杂的View时候,很容易变得卡顿。
下图是一个普通的列表,为了提高体验,超过屏幕部分的部分其实是可以回收的:
为了将超过屏幕的部分给回收,Tumblr采用了以下2个设计来提高性能并减少内存。
Viewholders能够被相同或者不同类型的models所共享,上图中item#1和item#2的body viewholder就可以被共享。
一个Model能拥有不同的Viewholders,一个item对应一个Model,所以一个item也就能拥有无数个body viewholders。
这样做的结果是能使用最少数量的ViewHolders来最大化内存的使用率,同时还能减少内存的使用。
第三个问题:Graywater原理是什么?
在讨论这个问题前,我们先眼熟一下这张图,这张图概括了Graywater的设计。
这张图里面涉及到了5个类:
- Model
- ViewHolder
- ViewHolderCreator
- Binder
- ItemBinder
Model和ViewHolder是在使用RecyclerView时本来就会用到的,但是这2个类,因为Graywater的设计原因,会跟在RecyclerView.Adapter使用时有一些区别。在下一篇基础实操篇中可以看到。同时为了实现问题2中的2个特点,Tumblr在这两者间添加了Binder类。来把model(T)数据绑定到 viewholder (VH)视图上。
+-------+ +--------+ +------------+
| Model | --> | Binder | --> | ViewHolder |
+-------+ +--------+ +------------+
同时,Graywater也不再追求单一的model与viewholder之间一对一的关系,因为单一的model只能产生单一的视图。而是将这两者之间的关系变成了一对多的关系,这样Adapter的灵活度就大大提升,一个Item就可以有Head、Body和Footer(其中的ViewHolder可以任意添加,没有限制)。
+--------+ +------------+
/--> | Binder | --> | ViewHolder |
+-------+ +---+ / +--------+ +------------+
| Model | --> | ? | *----> | Binder | --> | ViewHolder |
+-------+ +---+ \ +--------+ +------------+
\--> | Binder | --> | ViewHolder |
+--------+ +------------+
为了管理这种一对多关系,所以又添加Itembinder这一个类。所以就有了最开始的原理图:
ItemBinder用来管理一个Item中所有的Binder类,有一个getBinderList()方法来返回所管理的binder集合。同时在实现ItemBinder接口时,需要传入Model的类型,ItemBinder需要知道它所对应的的数据类型(Model)是什么。
Binder<? super T, ? extends VH>
接口中会传入Model和ViewHolder的类型。Binder类就将model和ViewHolder联系了起来。
所以一环扣一环,各个类的关系也就建立起来了,下图可以更直观的展示:
图中还剩一个ViewHolderCreator
是干嘛的呢?
在RecyclerView.Adapter的onCreateViewHolder()
方法中需要创建ViewHolder
,这个时候ViewHolderCreator
就派上用场了。
ViewHolderCreator
是一种独立于model来创建viewholder的方式(在模型和视图之间具有一对一关系的其他库中,此代码将存在于模型中 ,例如Epoxy)。
针对某一个类型的Item,创建对应的5个基本类,并建立相应的关系,关系全部建立好之后,就可以开始分别实现,得到一个高性能的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()
方法创建ViewHolder,当然create()方法是由我们在实现ViewHolderCreator接口时来实现的。
也就是关系
+------------+ +-------------------+
| ViewHolder | <-- | ViewHolderCreator |
+------------+ +-------------------+
onBindViewHolder(RecyclerView.ViewHolder holder, int position)
这是RecyclerView.Adapter最核心的方法,Graywater通过Binder在这个方法中,将Model数据和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,把数据给到view)。从这里我们就看到,bind()方法是怎么使用的了。
最核心的代码:
binder.bind(result.item, holder, result.binderList, result.binderIndex, actionListener);
BinderResult是GraywaterAdapter中的一个内部类,拥有着与ViewHolder相关的Model、Binder的引用。
在binder和model不为空的情况下,将
- model(result.item)
- holder
- binder集合(result.binderList)
- 当前viewholder的位置(result.binderIndex)
- actionListener
作为参数传递到我们重写的bind()方法中,在bind方法中将数据model映射到view视图上,RecyclerView就能显示出数据了。
理论部分差不多就讲完了,下一篇就是实战了。
P.S.
Graywater Github地址
如果对你有帮助的话,点赞、评论、赞赏都是对我的鼓励,也是支持我写下去的动力,谢谢!