作者简介 原创微信公众号郭霖 WeChat ID: guolin_blog
大家周五好,提前祝大家周末愉快!
本篇来自老司机张旭童投稿,继续给大家带来了原创的开源库。本文是此开源库系列的第二篇(主要涉及DataBinding),所以文中的上文指系列的第一篇,想从头了解的朋友可以访问他的博客查看。
张旭童的博客地址:
http://blog.csdn.net/zxt0601
前言
在上文中,我们利用 Adapter模式 封装了一个库,能快速为 任意ViewGroup 添加 子View。有如下特点:
快速简单使用
支持任意ViewGroup
无耦合
无侵入性
Item支持多种类型
在库中V1.1.0版本,我也顺手加入了 RecyclerView、ListView、GridView 的通用 Adapter 功能,库地址:
https://github.com/mcxtzhang/all-base-adapter
现在V1.2.0版本发布,我又加入了我最近超爱的一个技术,DataBinding。
封装了一套一行代码实现花式列表的Adapter。即利用 DataBinding 实现 RecyclerView 中快速使用的 Adapter。
以后不管写多种type还是单type的列表,利用 DataBinding 和 本库,都只需要一行代码!
这里也算是安利 DataBinding 吧,真的超好用。还没使用的朋友们,在看到本文可以如此简单写花式列表后,建议去学习一下。先看用法吧,简单粗暴到没朋友。
用法
使用必读
BaseBindingAdapter 利用 DataBinding 提供的动态绑定技术,使用 BR.data 封装数据、BR.itemP 封装点击事件。所以对 layout 有以下要求:
layout中 数据name 起名data
layout中 点击事件Presenter 起名 itemP
比如:
1. 单Item列表
效果如图,顺带演示了 BaseBindingAdapter 封装的一些增删功能:
用法:
和其他 BaseAdapter 用法一致
构造函数只需要传入 context,datas,layout
mAdapter=newBaseBindingAdapter(this, mDatas,R.layout.item_db_single);
好了,列表已经出来了。我不骗你,就这一句话。如果需要设置点击事件(点击事件设置所有类型都一样,下不赘述):
特殊需求:如果有特殊需求,可传入两个泛型,重写onBindViewHolder搞事情:
2. 多Item同种数据类型列表
一般是像IM那种列表,虽然Item不同,但是数据结构是同一个。用法,一句话~效果如图:
用法:
数据结构(JavaBean)需实现 IBaseMulInterface接口,根据情况返回不同的layout。
构造函数只需要传入context,datas.
mAdapter=newBaseMulTypeBindingAdapter(this, mDatas);
复杂列表依然一句话:
特殊需求:如果有特殊需求,可传入数据结构的泛型,避免强转,重写 onBindViewHolder() 方法,但是 Binding类 不可避免的需要强转了:
3. 多Item、多种数据类型列表
各大APP首页,Banner、列表、推荐混排,数据结构肯定不同,但是依然只要一句代码搞定Adapter!效果如图:
用法:
数据结构(JavaBean)需分别实现 IBaseMulInterface接口,返回数据结构对应的layout。
构造函数只需要传入context,datas.
mAdapter=newBaseMulTypeBindingAdapter(this, mDatas);
特殊需求:如果有特殊需求,重写 onBindViewHolder()方法,但是 数据结构 和 Binding类 都不可避免的需要强转了:
4. 不能忘了上文的ViewGroup
对上文封装的 ViewGroup 类型 Adapter 也提供 DataBinding 的支持。当然还是流式布局搭配我自己的侧滑菜单控件。效果如图:
用法:和上文一样,只是 Adapter 换成 SingleBindingAdapter
如果需要设置点击事件:
mAdapter.setItemPresenter(newItemDelPresenter());
设计思路与实现
使用起来如此爽快,其实写起来也很简单。
注意 类BaseBindingAdapter 和 BaseMulTypeBindingAdapter 都不是 abstract 的,这说明我们不需要重写任何方法。
利用 DataBinding,我们在 BasexxxAdapter内部 和 xml 分别做View的创建和数据绑定的工作。
UML类图
先简要概括:
BaseBindingVH 继承自 RecyclerView.ViewHolder,持有 T extends ViewDataBinding类型的 mBinding 变量。利用 ViewDataBinding 我们将不用再写任何 ViewHolder。
BaseBindingAdapter,继承自 RecyclerView.Adapter,依赖 BaseBindingVH,onCreateViewHolder(ViewGroup parent, int viewType)方法 返回 BaseBindingVH 作为 ViewHolder。
内部持有三个重要变量:数据对应layout,数据集,Item点击事件处理类。数据对应layout 会在 onCreateViewHolder(ViewGroup parent, int viewType) 用到。剩下两个变量在 onBindViewHolder() 用到。对外暴漏 setItemPresenter(Object itemPresenter)供设置点击事件处理类。
IBaseMulInterface接口 和上文提到的一样,返回某个数据结构对应的layout,除此之外,本文还有一个十分tricky之处,利用返回的 R.layout.itemxxxx 作为 ItemViewType,在 BaseMulTypeBindingAdapter 会用到。
BaseMulTypeBindingAdapter 继承自 BaseBindingAdapter,但是它不再关心 mLayoutId 变量,它利用 IBaseMulInterface接口 返回的 R.layout.itemxxxx 作为 ItemViewType,这样在 onCreateViewHolder(ViewGroup parent, int viewType) 的时候,就可以直接用 viewType 构造出 ItemView。不再依赖 mLayoutId 变量。这是一个我很得意的设计,我在"优雅为RecyclerView增加HeaderView"一文中,也曾用过这个方法。
BaseBindingVH
BaseBindingVH 算是一个核心类,但是又十分简单。它继承自 RecyclerView.ViewHolder,持有由泛型传入的 T extends ViewDataBinding 类型的mBinding变量。
唯一构造函数,需要一个 T t 变量,然后调用 super() 传入 t.getRoot() 完成 itemView 的赋值。同时对 mBinding 变量赋值。对外暴漏 getBinding() 返回 mBinding 变量。
利用 ViewDataBinding 我们将不用再写任何 ViewHolder。
BaseBindingAdapter
BaseBindingAdapter,继承自 RecyclerView.Adapter,依赖 BaseBindingVH,将 BaseBindingVH 作为泛型传给 RecyclerView.Adapter。
同时 BaseBindingAdapter 本身接受两个泛型,。
泛型没有特殊需求可以不传
泛型D:是Bean类型,如果有就传。
泛型B:是对应的xml Layout的Binding类
传入不传入泛型的区别已经在第二节具体用法里进行了演示,不再赘述。内部持有三个重要变量:
数据对应layout int mLayoutId;
数据集 List mDatas;
Item点击事件处理类。Object ItemPresenter;
mLayoutId 和 mDatas 都由构造函数传入,没啥好说的。
对外暴漏 setItemPresenter(Object itemPresenter) 供设置点击事件处理类 ItemPresenter。ItemPresenter 是 Object 类型,这样才不care你set的Item点击事件处理类是什么鬼。
onCreateViewHolder(ViewGroup parent, int viewType) 方法返回 BaseBindingVH 作为 ViewHolder。
mLayoutId 会在 onCreateViewHolder(ViewGroup parent, int viewType) 用到,再根据泛型B强转成对应的 ViewDataBinding:
会在 onBindViewHolder() 方法里,利用 DataBinding 动态绑定 ViewDataBinding.setVariable(BR.itemP, ItemPresenter);为每个Item设置点击事件。
同时,数据也是同样在里面绑定的:setVariable(BR.data, mDatas.get(position))。重点代码如下:
BaseBindingAdapter 内部也封装了如下方法,方便数据刷新,增删(定向刷新)调用:
IBaseMulInterface接口
IBaseMulInterface接口 和上文提到的一样,返回某个数据结构对应的layout.
除此之外,本文还有一个十分tricky之处,利用返回的 R.layout.itemxxxx 作为 ItemViewType,在 BaseMulTypeBindingAdapter 会用到。因为不同的 R.layout.itemxxxx 对于 RecyclerView 来说一定是不同的Item。
BaseMulTypeBindingAdapter
多种ItemType的Base类
BaseMulTypeBindingAdapter 继承自 BaseBindingAdapter,但是它不再关心 mLayoutId 变量。因此它传给父类的 泛型B 就是 ViewDataBinding类 本身。解释如下:
基类的泛型B:不用传,因为多种 ItemType 肯定 Layout 长得不一样,那么 Binding类 也不一样,传入没有任何意义
泛型T:多Item 多Bean 情况可以不传。如果只有一种Bean类型,可以传入Bean,实现 IBaseMulInterface接口。或者传入 IBaseMulInterface接口,可以拿到 getItemLayoutId(),但是通过 getItemViewType(int position) 一样。所以多Item多Bean建议不传。传入不传入泛型的区别已经在第二节具体用法里进行了演示,不再赘述。
getItemViewType() 直接返回 IBaseMulInterface接口 的返回值。
在 onCreateViewHolder(ViewGroup parent, int viewType) 的时候,直接用 viewType 构建 ViewDataBinding(ItemView)。不再依赖 mLayoutId 变量。
完整代码如下:
ViewGroup Adapter的实现
单item
继承 SingleAdapter,增加 ItemPresenter,在 getView() 完成View创建和绑定。
多Item
更简单了,继承 SingleBindingAdapter。重写getView()即可:
总结
本文利用 DataBinding 的 ViewDataBinding 直接略去写 ViewHolder。
利用 Object类型 的 ItemPresenter,兼容解决了点击事件的设置。
最得意的设计,还是利用 R.layout.xxxx 这些布局文件 int类型 的 RID,作为 ItemViewType,一箭双雕。
DataBinding 很强,希望大家快点拥抱它。
to do list
ViewGroup Adapter 考虑加入复用缓存池
ViewGroup Adapter ,考虑替换onBindView()的ItemView->通用的ViewHolder,这样可以少写一些findViewById()代码
整合 DataBinding 的通用Adapter入库。(已完成)
完善 RecyclerView、ListView的通用Adapter,支持多种ItemViewType。
加入一些自定义ViewGroup入库,例如流式布局,九宫格,Banner轮播图。
完。。。。。。。。。。。。。。。。。。。。。
文章原创作者GuoLin 书籍推荐
郭林大神原创android 书籍:《第一行代码 android》