DataBinding的使用总结-进阶篇(recyclerView)

基础篇

项目代码:放在前面以防有人看不到   https://github.com/summerhotready/KotlinCol/tree/bindingOrigin

基础篇讲述的是如何配置和使用db,并提供了稳定版本的参数,下面我们聊一聊使用最普遍的recyclerView是如何使用DB的

我们使用RV一般有两种情况,单布局和多布局,单布局简单明晰,就易用性来说比不上ListView,但倘若要做上下移动动画RV可就实在方便多了,RV的动画将放在另一篇写动画的帖子中总结


单布局

按照我们之前的书写方式,一个RecyclerView的展示包括:一个对应的Adapter,Modle,ViewHolder和adapter_item.xml。

组成List数组后装配Adapter,Adapter使用绑定好了的ViewHolder来建立item。

你需要做的是:

1.写好item.xml布局,并给各子view赋予modle的值

2.在ViewHolder中引用该Item的Binding并返回mBinding.root以替代ItemsView

3.在adapter的binding中赋值给holder.mBinding中绑定的modle

4.我想说的重点是监听

网上最多的解释是建立一个Holder类,通过在xml引用调用,我呢不想这样,我写了个接口,然后在xml中引用了,果然也成了。

public interface OnAdapterItemClickListener {
    //type
    int TYPE_EMAIL = 1;
    int TYPE_PHONE = 2;
    void onClickSave(int type,String... value);
    void onClickImportant(int type,String... value);
    void onClickSend(int type,String... values);
}

xml引用

引入

<variable
    name="listener"
    type="com.guoxd.kot.listener.OnAdapterItemClickListener"/>
使用
android:onClick="@{(view)->listener.onClickSend(listener.TYPE_EMAIL,data.email,data.name)}"

实现

要注意的是我还没找到kotlin中匿名类的写法,所以我写了一个类实现了它,顺便测试了一下String... 的kotlin实现

class Listener : OnAdapterItemClickListener{
    override fun onClickImportant(type: Int, vararg value: String?) {
        for( str in value){
            Log.i("Listener","onClickImportant Click:"+type+" string:"+str)
        }
    }
    override fun onClickSave(type: Int, vararg value: String?) {
        for( str in value){
            Log.i("Listener","onClickSave Click:"+type+" string:"+str)
        }
    }
    override fun onClickSend(type: Int, vararg values: String?) {
        for( str in values){
            Log.i("Listener","onClickSend Click:"+type+" string:"+str)
        }
    }
}

赋值

adapter.listener = Listener()
Adapter中:

声明:var listener: OnAdapterItemClickListener?=null;

传递:onBindViewHolder中调用 holder?.bindListener(listener)

赋值:ViewHolder中的bindListener函数

fun bindListener(listener : OnAdapterItemClickListener?){
    mBinding.setVariable(BR.listener,listener)
}

多布局

我参考了简书上一篇博客,一开始我以为它是服用Adapter和ViewHolder,来实现多个RecyclerView共用一套Adapter的问题,后来我发现不是,他解决的是一个RecyclerView中使用多种布局的问题。

我在他文章的基础上做了改变,对于数据源Bean,提供了抽象类BaseBean,并声明一个抽象方法:getViewType()用来提供该数据源使用的layout,在我的设计中使用抽象类比原文的声明接口更好理解和维护。关于接口和抽象类的定论在此不议,仅仅因为无需再继承其他的类所以此处用抽象类。

public abstract class BaseBean {
    public abstract int getViewType();//要注意使用public声明
}
在单布局的基础上我们可以制作多布局,首先最重要的一点,将再ViewHolder中绑定layout的步骤挪到Adapter中,通过传入ViewDataBinding的子类来实现,并且及其重要的一点,在ViewHolder中需要对满足某一条件的modle赋值:

open class ContactBean(var name : String,var number : String,var Address : String,var isImportant : Boolean) : BaseBean(){
    override fun getViewType(): Int {//回传
        return R.layout.adapter_contact_item
    }
    init {
        isImportant = false
    }
}

以上面联系人为例子,编写ViewHolder

class ViewHolder(val mBinding : ViewDataBinding ) : RecyclerView.ViewHolder(mBinding.root){//替代的是ItemsView
    fun getBinding() : ViewDataBinding {//传入ViewDataBinding的子类
        return mBinding
    }
    fun bindData(bean:BaseBean){//赋值,BR是DB自动生成的,并看不到,可能会有多个可以相互替代不过选择根目录下的BR就可以了
        mBinding.setVariable(BR.data,bean)//这一步是赋值,将BaseBean的实现/子类与data进行绑定,需要注意的是所有的adapter_item.xml的填充数据都要命名为data
    }
}

需要注意的是BR中的内容需要重新编译才会发生改变
绑定,Adapter中首先要重写getItemViewType,以确保onCreateViewHolder中viewType的值非0.

 override fun getItemViewType(position: Int): Int {
        return mDatas[position].getViewType()
    }


// viewType:重写getItemViewType后才不是默认的0
    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
        val binding : ViewDataBinding = DataBindingUtil.inflate(
                LayoutInflater.from(mContext), viewType,parent,false )
        return ViewHolder(binding)
    }

只有重写了该方法create中获得的viewType的值才不会总是 0
这样一来原本一一对应的adapter和viewholder被抽象出来,binding这一步被放到data中,viewholder反回一整个binding数据,而后在adapter中使用接口将复杂操作在引用中实现。
之后我测试了使用parent?.childCount获取,但这样有个问题是只能呈现出页面展示的item序号,比如页面能展示4条,他只会生成5个于是我有个想法,在一个item内写两种布局,引入两个data,通过判空方式显示data的值,当你一个页面有五六种布局的时候会比较麻烦,所以还是重写这个方法最好

Adapter复用

下面谈一谈我真正想说的Adapter的复用,我是想实现一套adapter和viewHolder在多个RecyclerView上的使用,通过上一步骤,解耦了ViewHolder和molder,所以下一步是通过钩子,将Adapter的onBindViewHolder传递到activity中,通过传递父类的数据类型,在处理页面进行对应实现。
参考 MultAdapter,这部分代码为什么不放出?因为跟详细讲解的多布局是一样的,在那基础上引入了一个listener,要是看不懂去看看代码吧。
总结一下,复用的越多要写得越少,留给实现要做得越多。你可能觉得这是废话,最初我看到的时候也觉得是废话,等到写了许多代码才觉得这是实践出真知。


你可能感兴趣的:(android前端笔记)