Android快速开发偷懒必备 支持DataBinding啦~爽炸,一行实现花式列表

但使书种多,会有岁稔时。这篇文章主要讲述Android快速开发偷懒必备 支持DataBinding啦~爽炸,一行实现花式列表相关的知识,希望能为你提供帮助。

本篇文章已授权微信公众号 guolin_blog ( 郭霖) 独家发布
转载请标明出处:
http://blog.csdn.net/zxt0601/article/details/53618694
本文出自:【张旭童的博客】(http://blog.csdn.net/zxt0601)
代码传送门: 喜欢的话, 随手点个star。多谢
https://github.com/mcxtzhang/all-base-adapter
概述 在前文快速开发偷懒必备( 一) 中, 我们利用Adapter模式封装了一个库, 能快速为任意ViewGroup添加子View。
有如下特点:
* 快速简单使用
* 支持任意ViewGroup
* 无耦合
* 无侵入性
* Item支持多种类型
在库中V1.1.0版本, 我也顺手加入了RecyclerView、ListView、GridView的通用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
如:
< layout xmlns:android= " http://schemas.android.com/apk/res/android" xmlns:app= " http://schemas.android.com/apk/res-auto" xmlns:tools= " http://schemas.android.com/tools" > < data> < variable name= " itemP" type= " mcxtzhang.commonviewgroupadapter.databinding.rv.single.DBSingleActivity.SingleItemPresenter" /> < variable name= " data" type= " mcxtzhang.commonviewgroupadapter.databinding.rv.single.DBSingleBean" /> < /data> < LinearLayout android:layout_width= " match_parent" android:layout_height= " wrap_content" android:layout_margin= " 1dp" android:background= " @ color/colorAccent" android:onClick= " @ {v-> itemP.onItemClick(data)}" android:orientation= " horizontal" > < ImageView android:id= " @ + id/ivAvatar" android:layout_width= " 200dp" android:layout_height= " 200dp" app:netUrl= " @ {data.avatar}" tools:src= " @ mipmap/ic_launcher" /> < TextView android:id= " @ + id/tvName" android:layout_width= " wrap_content" android:layout_height= " wrap_content" android:text= " @ {data.name}" tools:text= " 测试多种" /> < /LinearLayout> < /layout>

1 单Item列表
效果如图: 顺带演示了BaseBindingAdapter封装的一些增删功能。
Android快速开发偷懒必备 支持DataBinding啦~爽炸,一行实现花式列表

文章图片

用法: 和其他BaseAdapter用法一致:
* 构造函数只需要传入context, datas, layout
mAdapter = new BaseBindingAdapter(this, mDatas, R.layout.item_db_single);

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

/** * ★ Item点击事件P */ public class SingleItemPresenter { public void onItemClick(DBSingleBean data) { data.setName(" 修改之后立刻见效" ); } }

特殊需求: 【Android快速开发偷懒必备 支持DataBinding啦~爽炸,一行实现花式列表】如果有特殊需求, 可传入两个泛型, 重写onBindViewHolder搞事情:
// ★泛型D:是Bean类型, 如果有就传。泛型B:是对应的xml Layout的Binding类 mAdapter = new BaseBindingAdapter< DBSingleBean, ItemDbSingleBinding> (this, mDatas, R.layout.item_db_single) { @ Override public void onBindViewHolder(BaseBindingVH< ItemDbSingleBinding> holder, int position) { //★super一定不要删除 super.onBindViewHolder(holder, position); //如果有特殊需求, 可传入两个泛型, 重写onBindViewHolder搞事情。 ItemDbSingleBinding binding = holder.getBinding(); DBSingleBean data = mDatas.get(position); } };

2 多Item同种数据类型列表
一般是像IM那种列表, 虽然Item不同, 但是数据结构是同一个。用法, 一句话~
效果如图:
Android快速开发偷懒必备 支持DataBinding啦~爽炸,一行实现花式列表

文章图片

用法:
  • 数据结构( javaBean) 需实现IBaseMulInterface接口,根据情况返回不同的layout。
  • 构造函数只需要传入context, datas.
mAdapter = new BaseMulTypeBindingAdapter(this, mDatas);

复杂列表依然一句话。
public class MulTypeSingleBean extends BaseObservable implements IBaseMulInterface { private String avatar; private String name; private boolean receive; @ Override public int getItemLayoutId() { if (isReceive()) { return R.layout.item_db_mul_1; } else { return R.layout.item_db_mul_2; } } }

特殊需求: 如果有特殊需求, 可传入数据结构的泛型, 避免强转, 重写onBindViewHolder()方法,但是Binding类 不可避免的需要强转了:
mAdapter = new BaseMulTypeBindingAdapter< MulTypeSingleBean> (this, mDatas) { @ Override public void onBindViewHolder(BaseBindingVH< ViewDataBinding> holder, int position) { super.onBindViewHolder(holder, position); //如果有特殊需求, 可传入数据结构的泛型, 避免强转 MulTypeSingleBean data = mDatas.get(position); //Binding类 不可避免的需要强转了 ViewDataBinding binding = holder.getBinding(); switch (data.getItemLayoutId()) { case R.layout.item_db_mul_1: ItemDbMul1Binding itemDbMul1Binding = (ItemDbMul1Binding) binding; break; case R.layout.item_db_mul_2: ItemDbMul2Binding itemDbMul2Binding = (ItemDbMul2Binding) binding; break; }} };

3 多Item、多种数据类型列表
各大APP首页, Banner、列表、推荐混排, 数据结构肯定不同, 但是依然只要一句代码搞定Adapter!
效果如图:
Android快速开发偷懒必备 支持DataBinding啦~爽炸,一行实现花式列表

文章图片

用法:
  • 数据结构( JavaBean) 需分别实现IBaseMulInterface接口,返回数据结构对应的layout。
  • 构造函数只需要传入context, datas.
mAdapter = new BaseMulTypeBindingAdapter(this, mDatas);

public class MulTypeMulBean1 extends BaseObservable implements IBaseMulInterface { private String avatar; private String name; @ Override public int getItemLayoutId() { return R.layout.item_db_mulbean_1; } }

public class MulTypeMulBean2 extends BaseObservable implements IBaseMulInterface { private String background; @ Override public int getItemLayoutId() { return R.layout.item_db_mulbean_2; } }

特殊需求: 如果有特殊需求, 重写onBindViewHolder()方法,但是数据结构 和 Binding类 都不可避免的需要强转了:
mAdapter = new BaseMulTypeBindingAdapter(this, mDatas) { @ Override public void onBindViewHolder(BaseBindingVH holder, int position) { super.onBindViewHolder(holder, position); //如果有特殊需求 重写onBindViewHolder方法 // 数据结构 和 Binding类 都不可避免的需要强转了 ViewDataBinding binding = holder.getBinding(); switch (getItemViewType(position)) { case R.layout.item_db_mul_1: ItemDbMul1Binding itemDbMul1Binding = (ItemDbMul1Binding) binding; MulTypeMulBean1 data1 = (MulTypeMulBean1) mDatas.get(position); break; case R.layout.item_db_mul_2: ItemDbMul2Binding itemDbMul2Binding = (ItemDbMul2Binding) binding; MulTypeMulBean2 data2 = (MulTypeMulBean2) mDatas.get(position); break; } } };

4 不能忘了上文的ViewGroup呀
对上文封装的ViewGroup类型Adapter也提供DataBinding的支持。
效果如图: 当然还是流式布局搭配史上集成最叼侧滑菜单控件。
Android快速开发偷懒必备 支持DataBinding啦~爽炸,一行实现花式列表

文章图片

用法: 和上文快速开发偷懒必备( 一) 一样, 只是Adapter换成SingleBindingAdapter
mAdapter = new SingleBindingAdapter< > (this, mDatas = iniDatas(), R.layout.item_db_flow_swipe);

如果需要设置点击事件:
mAdapter.setItemPresenter(new ItemDelPresenter());

设计思路与实现 使用起来如此爽快, 其实写起来也很简单。
注意类BaseBindingAdapterBaseMulTypeBindingAdapter都不是abstract的, 这说明我们不需要重写任何方法。
利用DataBinding, 我们在BasexxxAdapter内部和xml分别做View的创建和数据绑定的工作。
UML类图
Android快速开发偷懒必备 支持DataBinding啦~爽炸,一行实现花式列表

文章图片

先简要概括
  • BaseBindingVH继承自RecyclerView.ViewHolder, 持有T extends ViewDataBinding类型的mBinding变量。利用ViewDataBinding我们将不用再写任何ViewHolder
  • BaseBindingAdapter, 继承自RecyclerView.Adapter,依赖BaseBindingVHonCreateViewHolder(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
public class BaseBindingVH< T extends ViewDataBinding> extends RecyclerView.ViewHolder { protected final T mBinding; public BaseBindingVH(T t) { super(t.getRoot()); mBinding = t; }public T getBinding() { return mBinding; } }

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;
mLayoutIdmDatas都由构造函数传入, 没啥好说的。
对外暴漏setItemPresenter(Object itemPresenter)供设置点击事件处理类ItemPresenter
ItemPresenterObject类型, 这样才不care你set的Item点击事件处理类是什么鬼。
onCreateViewHolder(ViewGroup parent, int viewType)方法返回BaseBindingVH作为ViewHolder
mLayoutId会在onCreateViewHolder(ViewGroup parent, int viewType)用到,再根据泛型B强转成对应的ViewDataBinding
BaseBindingVH< B> holder = new BaseBindingVH< B> ((B) DataBindingUtil.inflate(mInfalter, mLayoutId, parent, false));

会在onBindViewHolder()方法里, 利用DataBinding动态绑定ViewDataBinding.setVariable(BR.itemP, ItemPresenter); 为每个Item设置点击事件。
同时, 数据也是同样在里面绑定的: setVariable(BR.data, mDatas.get(position))
重点代码如下:
public class BaseBindingAdapter< D, B extends ViewDataBinding> extends RecyclerView.Adapter< BaseBindingVH< B> > { protected Context mContext; protected int mLayoutId; protected List< D> mDatas; protected LayoutInflater mInfalter; //用于设置Item的事件Presenter protected Object ItemPresenter; public BaseBindingAdapter(Context mContext, List mDatas, int mLayoutId) { this.mContext = mContext; this.mLayoutId = mLayoutId; this.mDatas = mDatas; this.mInfalter = LayoutInflater.from(mContext); }@ Override public BaseBindingVH< B> onCreateViewHolder(ViewGroup parent, int viewType) { BaseBindingVH< B> holder = new BaseBindingVH< B> ((B) DataBindingUtil.inflate(mInfalter, mLayoutId, parent, false)); onCreateViewHolder(holder); return holder; }/** * 如果需要给Vh设置监听器啥的 可以在这里 * * @ param holder */ public void onCreateViewHolder(BaseBindingVH< B> holder) {}/** * 子类除了绑定数据, 还要设置监听器等其他操作。 * 可以重写这个方法, 不要删掉super.onBindViewHolder(holder, position); * * @ param holder * @ param position */ @ Override public void onBindViewHolder(BaseBindingVH< B> holder, int position) { holder.getBinding().setVariable(BR.data, mDatas.get(position)); holder.getBinding().setVariable(BR.itemP, ItemPresenter); holder.getBinding().executePendingBindings(); } /** * 用于设置Item的事件Presenter * * @ param itemPresenter * @ return */ public BaseBindingAdapter setItemPresenter(Object itemPresenter) { ItemPresenter = itemPresenter; return this; } }

BaseBindingAdapter内部也封装了如下方法, 方便数据刷新, 增删(定向刷新)调用:
/** * 刷新数据, 初始化数据 * * @ param list */ public void setDatas(List< D> list) { if (this.mDatas != null) { if (null != list) { List< D> temp = new ArrayList< D> (); temp.addAll(list); this.mDatas.clear(); this.mDatas.addAll(temp); } else { this.mDatas.clear(); } } else { this.mDatas = list; } notifyDataSetChanged(); }/** * 删除一条数据 * 会自动定向刷新 * * @ param i */ public void remove(int i) { if (null != mDatas & & mDatas.size() > i & & i > -1) { mDatas.remove(i); notifyItemRemoved(i); } }/** * 添加一条数据 至队尾 * 会自动定向刷新 * * @ param data */ public void add(D data) { if (data != null & & mDatas != null) { mDatas.add(data); notifyItemInserted(mDatas.size()); } }/** * 在指定位置添加一条数据 * 会自动定向刷新 * < p> * 如果指定位置越界, 则添加在队尾 * * @ param position * @ param data */ public void add(int position, D data) { if (data != null & & mDatas != null) { if (mDatas.size() > position & & position > -1) { mDatas.add(position, data); notifyItemInserted(position); } else { add(data); } } }/** * 加载更多数据 * * @ param list */ public void addDatas(List< D> list) { if (null != list) { List< D> temp = new ArrayList< D> (); temp.addAll(list); if (this.mDatas != null) { this.mDatas.addAll(temp); } else { this.mDatas = temp; } notifyDataSetChanged(); }}

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构建ViewDataBindingItemView) 。不再依赖mLayoutId变量。
这是一个我很得意的设计, 我在优雅为RecyclerView增加HeaderView一文中, 也曾用过这个方法添加头部。
完整代码如下:
public class BaseMulTypeBindingAdapter< T extends IBaseMulInterface> extends BaseBindingAdapter< T, ViewDataBinding> {public BaseMulTypeBindingAdapter(Context mContext, List< T> mDatas) { super(mContext, mDatas); }@ Override public int getItemViewType(int position) { return mDatas.get(position).getItemLayoutId(); }@ Override public BaseBindingVH< ViewDataBinding> onCreateViewHolder(ViewGroup parent, int viewType) { BaseBindingVH< ViewDataBinding> holder = new BaseBindingVH< ViewDataBinding> (DataBindingUtil.inflate(mInfalter, viewType, parent, false)); onCreateViewHolder(holder); return holder; } }

ViewGroup Adapter的实现 单item
继承SingleAdapter, 增加ItemPresenter, 在getView()完成View创建和绑定。
public class SingleBindingAdapter< D, B extends ViewDataBinding> extends SingleAdapter< D> { //用于设置Item的事件Presenter protected Object ItemPresenter; /** * 用于设置Item的事件Presenter * * @ param itemPresenter * @ return */ public SingleBindingAdapter setItemPresenter(Object itemPresenter) { ItemPresenter = itemPresenter; return this; }public SingleBindingAdapter(Context context, List< D> datas, int itemLayoutId) { super(context, datas, itemLayoutId); }//重写利用DataBinding做 @ Override public View getView(ViewGroup parent, int pos, D data) { ViewDataBinding binding = DataBindingUtil.inflate(mInflater, mItemLayoutId, parent, false); View itemView = binding.getRoot(); onBindView(parent, itemView, data, pos); binding.setVariable(BR.data, data); binding.setVariable(BR.itemP, ItemPresenter); return itemView; }//空实现即可, 因为DataBinding的实现都是在xml里做 @ Override public void onBindView(ViewGroup parent, View itemView, D data, int pos) {} }

多Item: 更简单了, 继承SingleBindingAdapter。重写getView()即可。
public class MulTypeBindngAdapter< T extends IMulTypeHelper> extends SingleBindingAdapter< T, ViewDataBinding> {public MulTypeBindngAdapter(Context context, List< T> datas) { super(context, datas, -1); }//重写利用DataBinding做 @ Override public View getView(ViewGroup parent, int pos, T data) { ViewDataBinding binding = DataBindingUtil.inflate(mInflater, data.getItemLayoutId(), parent, false); View itemView = binding.getRoot(); onBindView(parent, itemView, data, pos); binding.setVariable(BR.data, data); binding.setVariable(BR.itemP, ItemPresenter); return itemView; } }

总结 代码传送门: 喜欢的话, 随手点个star。多谢
https://github.com/mcxtzhang/all-base-adapter
本文利用DataBindingViewDataBinding直接略去写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轮播图。
转载请标明出处:
http://blog.csdn.net/zxt0601/article/details/53618694
本文出自:【张旭童的博客】(http://blog.csdn.net/zxt0601)
代码传送门: 喜欢的话, 随手点个star。多谢
https://github.com/mcxtzhang/all-base-adapter

    推荐阅读