DataBinding(二)-实战

本篇文章基于上篇的基础文章,现在网上充斥着大量的复制粘贴文,各种关于databinding的误解,我写这系列的目的很简单,教你们怎么正确使用databinding,不要被网上的复制粘贴文坑。

databinding可以很轻松的帮我们实现视图和模型之间的绑定,但是他们是如何绑定的呢。
先来看一下文件结构:

看一个简单的例子:

activity_main.xml



    
        
        
        
        
        
    

    

        

            

这个xml文件会由系统自动生成一个与之对应的ActivityMainBinding文件(假如不使用类名或者),它继承的是android.databinding.ViewDataBinding类,实现了android.databinding.generated.callback.OnClickListener.Listener接口,这个接口就是在xml布局文件中的onclick方法,并且实现了android.databinding.generated.callback.OnLongClickListener.Listener,这个接口是xml布局文件中的onLongClick方法。

这个地方有一点要澄清,现在网上大部分教程都是写的databinding不支持onLongClick方法,这种说法是错误的,databinding现在已经支持大部分控件的接口实现,只是有一些还不支持IDE提示,所以在写的时候要手动去填写,另外在上一篇文章已经讲过,onLongClick需要返回一个boolean值,所以你自定义的方法类中必须也要为onlongclick方法设定为一个boolean值,否则编译器会报错。

下面是我定义的一个内部方法类(懒癌)

public class Presenter{
        public void addFragmentOne(){
            Log.d(TAG,"Click AddOne");
            ft=fm.beginTransaction();
            ft.add(R.id.fragment_container,new OneFragment()).commit();
        }

        public void addFragmentTwo(){
            Log.d(TAG,"Click AddTwo");
            ft=fm.beginTransaction();
            ft.replace(R.id.fragment_container,new TwoFragment()).commit();
        }

        public boolean onLongClick(){
            Log.d(TAG,"Click Long");
            return true;
        }
    }
02-21 01:37:02.519 3523-3523/com.saka.fragmentdemo D/MainActivity: Click Long

可以看到,正常安装并且运行实现了onLongClick方法。

BR文件概览

BR文件位于根目录下\app\build\generated\source\apt\debug\com\saka\fragmentdemo\BR.java位置。这是一个非常简单的常量类,每个ID对应于xml布局文件中的variable。在本例中的主要代码如下:

public class BR {
        public static final int _all = 0;
        public static final int presenter = 1;
        public static final int ssd = 2;
        public static final int text = 3;
}

所有的name都会自动生成一个int值(吐槽一下,为什么不是大写),有多少varibale就会对应生成多少ID。


        
        
        
        
        
    

Note:这里假如使用import导入的类或者为导入类设置别名均不会再BR文件中生成ID。

ActivityMainBinding概览

要了解Binding类,首先看它继承的父类

java.lang.Object
   ↳    android.databinding.BaseObservable
       ↳    android.databinding.ViewDataBinding 

它继承自BaseObservable,而BaseObsetvable直接继承自Object。
ViewDatabing这个父类是为生成databindingclass(也就是本例中的ActivityMainBinding)而出现的类。它必须实现 bind(View) 或者 inflate(LayoutInflater, int, ViewGroup, boolean)这两个静态方法中的一个。
看一下其中的几个方法:

void addOnRebindCallback (OnRebindCallback listener)

重新绑定字段调用的监听器,它允许暂停自动更新,但不会停止对executePendingBindings()的显示调用。

void executePendingBindings ()

更新已被挂起的任何具有绑定表达式的控件视图,必须运行在主线程中,通常recyclerview或者listview经常使用。

View getRoot ()

返回与binding关联的布局文件中的最外面的view,如果次帮帝国是用于merge布局文件,将返回第一个根标签。在fragment的绑定或者自定义view的绑定中使用的较多。

boolean hasPendingBindings ()

返回一个是否在主线程中等待被刷新的数据。

void invalidateAll ()

使所有绑定表达式无效,并请求新的重新绑定以刷新UI。

void removeOnRebindCallback (OnRebindCallback listener)

移除在 addOnRebindCallback(OnRebindCallback)中所有的监听器。

boolean setVariable (int variableId, Object value)

绑定值。variableId是BR文件中的id,value是你设定的类的实例。
返回的值假如为true表示你已经成功绑定。

void unbind ()

为表达式移除绑定监听器。

void finalize ()

这是一个protected方法,很少使用,但是讲一下原理:
看过thinkinjava的同学应该知道这一章,这个方法是在系统gc的时候调用的,但是我们很少在其中写方法,因为这个方法不确定会不会被调用。

当垃圾回收器确定当前的对象没有引用并且需要回收时,在ViewDataBinding的子类中就会调用该方法执行清理操作。

上面的方法中主要看一下其中几个在ActivityMainBinding中的继承使用:

setVariable

系统生成的setVariable方法已经自动启动了责任链模式,与之对应的系统会自动生成相应的getter和setter方法。本例中使用了Presenter和Ssd两个名字(但是是同一个类),方法如下:

public boolean setVariable(int variableId, Object variable) {
        switch(variableId) {
            case BR.text :
                setText((com.saka.fragmentdemo.models.Text) variable);
                return true;
            case BR.presenter :
                setPresenter((com.saka.fragmentdemo.MainActivity.Presenter) variable);
                return true;
            case BR.ssd :
                return true;
        }
        return false;
    }

此处需要注意的是假如你在xml文件没有使用某个variable,但是你在java文件中定义了它,

binding= DataBindingUtil.setContentView(this,R.layout.activity_main);
        binding.setPresenter(new Presenter());
        binding.setSsd(new Presenter());

系统会生成ssd的getter和setter方法,但是在setVariable方法中不会调用,因为你没有在xml中是使用这个variable,自动被系统忽略。也是精简的一种办法。
当然你可以直接调用setPresenter方法来绑定数据,和setVarible同样的作用,而且比它还少了很多步骤,推荐书hi用setPresenter方法。

_internalCallback

这个方法是用来绑定监听回调的。首先在xml文件中定义的事件方法都会在binding文件中生成一个对应的调用方法(例如onclik会生成_internalCallbackOnClick方法,onLongClick会生成_internalCallbackOnLongClick方法),并且会为每个回调方法指定一个sourceId(指定方法稍后讲),通过判断sourceId,来确定调用哪个方法。

public final void _internalCallbackOnClick(int sourceId , android.view.View callbackArg_0) {
        switch(sourceId) {
            case 3: {
                com.saka.fragmentdemo.MainActivity.Presenter presenter = mPresenter;
            
                boolean presenterObjectnull = false;
                presenterObjectnull = (presenter) != (null);
                if (presenterObjectnull) {
                    presenter.addFragmentTwo();
                }
                break;
            }
            case 2:
                break;
           
        }
    }

这个方法是onClick生成的对应binging文件中的方法。注意你自定义的方法中假如传参数的话会自动添加到你的方法中去。presenter.addFragmentTwo(10);

executeBindings

这个是用来绑定和监听数据的方法

 // batch finished
        if ((dirtyFlags & 0x9L) != 0) {
            // api target 1

            android.databinding.adapters.TextViewBindingAdapter.setText(this.addOne, btn1Text);
            android.databinding.adapters.TextViewBindingAdapter.setText(this.addTwo, btn2Text);
        }

这例的this.addOne就是button1,btn1Text获取的是variable中text的数据,可以看到源码中已经自动判断是否为空了,省了我们自己的步骤。

if ((dirtyFlags & 0x9L) != 0) {



                if (text != null) {
                    // read text.btn2
                    btn2Text = text.getBtn2();
                    // read text.btn1
                    btn1Text = text.getBtn1();
                }
        }

所有的监听回到方法类

此文件位于generated.callback文件夹下,这个文件夹包含了所有的回调方法类,类似于(OnClickListener,OnLongClickListener)。
这个文件实现了view.OnClickListener接口,所以可以被bingding类实现,它的功能就是添加sourceId。在binding文件中绑定:

public OnClickListener(Listener listener, int sourceId) {
        mListener = listener;
        mSourceId = sourceId;
    }
mCallback1 = new android.databinding.generated.callback.OnLongClickListener(this, 1);

你可能感兴趣的:(DataBinding(二)-实战)