DataBinding(二)-实战

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

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

看一个简单的例子:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="presenter"
            type="com.saka.fragmentdemo.MainActivity.Presenter"/>
        <variable
            name="text"
            type="com.saka.fragmentdemo.models.Text"/>
        <variable
            name="ssd"
            type="com.saka.fragmentdemo.MainActivity.Presenter"/>
        <import type="com.saka.fragmentdemo.MainActivity.Presenter"/>
        <import type="com.saka.fragmentdemo.MainActivity.Presenter"
            alias="jjjj"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.saka.fragmentdemo.MainActivity">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/add_one"
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:layout_weight="1"
                android:text="@{text.btn1}"
                android:textSize="10sp"
                android:onLongClick="@{()->presenter.onLongClick()}"
                android:onClick="@{()->presenter.addFragmentOne(10)}"/>

            <Button
                android:id="@+id/add_two"
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:layout_weight="1"
                android:text="@{text.btn2}"
                android:textSize="10sp"
                android:onClick="@{()->presenter.addFragmentTwo()}"/>
        </LinearLayout>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="20dp"
            android:background="@color/colorAccent"
            />
        <FrameLayout
            android:id="@+id/fragment_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>
</layout>

这个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。

<data>
        <variable
            name="presenter"
            type="com.saka.fragmentdemo.MainActivity.Presenter"/>
        <variable
            name="text"
            type="com.saka.fragmentdemo.models.Text"/>
        <variable
            name="ssd"
            type="com.saka.fragmentdemo.MainActivity.Presenter"/>
        <import type="com.saka.fragmentdemo.MainActivity.Presenter"/>
        <import type="com.saka.fragmentdemo.MainActivity.Presenter"
            alias="jjjj"/>
    </data>

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);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容