DataBinding:一行实现花式列表

来源:互联网 发布:vb自动登录弹出页面 编辑:程序博客网 时间:2024/04/29 22:28

今日科技快讯

谷歌联合LG于今日发布两款AndroidWear 2.0智能手表Watch Sport和Watch Style。谷歌称:Watch Sport是有史以来“性能最强的Android Wear手表”。它支持近场通讯(NFC)技术,可用于支付,使用GPS追踪健身情况并进行导航,并为用户的健身配备了心率传感器,支持蜂窝连接等。

作者简介

大家周五好,提前祝大家周末愉快!

本篇来自老司机 张旭童 投稿,继续给大家带来了原创的开源库。本文是此开源库系列的第二篇(主要涉及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 = new BaseBindingAdapter(this, mDatas, R.layout.item_db_single);

好了,列表已经出来了。我不骗你,就这一句话。如果需要设置点击事件(点击事件设置所有类型都一样,下不赘述):

特殊需求:如果有特殊需求,可传入两个泛型,重写 onBindViewHolder 搞事情:

2. 多Item同种数据类型列表

一般是像IM那种列表,虽然Item不同,但是数据结构是同一个。用法,一句话~效果如图:

用法:

  • 数据结构(JavaBean)需实现 IBaseMulInterface接口,根据情况返回不同的layout。

  • 构造函数只需要传入context,datas.

mAdapter = new BaseMulTypeBindingAdapter(this, mDatas);

复杂列表依然一句话:

特殊需求:如果有特殊需求,可传入数据结构的泛型,避免强转,重写 onBindViewHolder() 方法,但是 Binding类 不可避免的需要强转了:

3. 多Item、多种数据类型列表

各大APP首页,Banner、列表、推荐混排,数据结构肯定不同,但是依然只要一句代码搞定Adapter!效果如图:

用法:

  • 数据结构(JavaBean)需分别实现 IBaseMulInterface接口,返回数据结构对应的layout。

  • 构造函数只需要传入context,datas.

mAdapter = new BaseMulTypeBindingAdapter(this, mDatas);

特殊需求:如果有特殊需求,重写 onBindViewHolder()方法,但是 数据结构 和 Binding类 都不可避免的需要强转了:

4. 不能忘了上文的ViewGroup

上文封装的 ViewGroup 类型 Adapter 也提供 DataBinding 的支持。当然还是流式布局搭配我自己的 侧滑菜单控件。效果如图:

用法:上文一样,只是 Adapter 换成 SingleBindingAdapter

如果需要设置点击事件:

mAdapter.setItemPresenter(new ItemDelPresenter());

设计思路与实现

使用起来如此爽快,其实写起来也很简单。

注意 类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, B extends ViewDataBinding>。

  • 泛型没有特殊需求可以不传

  • 泛型D:是Bean类型,如果有就传。

  • 泛型B:是对应的xml Layout的Binding类

传入不传入泛型的区别已经在第二节具体用法里进行了演示,不再赘述。内部持有三个重要变量:

  • 数据对应layout int mLayoutId;

  • 数据集 List<D> 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轮播图。

更多

每天学习累了,看些搞笑的段子放松一下吧。关注最具娱乐精神的公众号,每天都有好心情。

如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号:

原创粉丝点击