Android Databinding(一)

2015年12月24日

[TOC]

1、环境需要:

1.Android 2.1 (API level 7+)
2.Gradle 1.5.0-alpha1
3.Android Studio 1.3

2、环境搭建

在build.gradle的android中加入如下字段,等待系统重新编译。

android{
        ...
        dataBinding {
            enabled = true
        }
        ...
}

3、快速开始

1、编写布局布局文件
和传统的布局文件不同,databinding的布局文件的跟标签为layout,他有两个子标签,分别为data和原始布局标签,也就是说在原来的布局基础上多加了一层layout,然后里面又多了一个data标签。在写完布局文件之后别忘记MakeProject一下,以便系统自动生成对应的类,类名为布局文件的名字首字母大写。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 配置变量,name字段为下面想要引用的类,type为全类名,
    AS中快捷键ctrl+shift+alt+c -->
    <data>
        <variable
            name="person"
            type="com.znke.hellodatabinding.Person"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <!-- 需要填充的字段用@{}表示 -->
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="25sp"
            android:text="@{person.name}"
            />
        <!-- 这里要转换一下,不然会引用int值所对应的R文件中的id -->
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="25sp"
            android:text="@{String.valueOf(person.age)}"
            />
    </LinearLayout>
</layout>

2、编写数据对象
一个简单POJO即可

public class Person {
    public final String name;
    public final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

3、在Acticity中进行绑定
在Acticity的onCreate(一个参数)方法里面进行绑定。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //当编写完布局文件的时候,他会自动生成一个对应的类,名字为布局文件名称+Binding
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        Person person = new Person("liucl", 22);
        //绑定
        binding.setPerson(person);
    }

*** 注意:***编译过中程如果出现xxx.databingding不存在,那么就是你布局文件写错了。仔细检查,现在as还不支持语法提示。

运行正常如下:


quickstart
quickstart

成功了,就是这三步!!!

4、绑定点击事件

Databinding支持把事件绑定到对象中,使用方法和上面大同小异
1、编写事件对象

public class ClickEvent {

    public void click(View v){
        Toast.makeText(v.getContext(), "测试成功 \n Context对象为"
                + v.getContext().toString()
                + "\n View对象为"
                + v.toString(),
                Toast.LENGTH_SHORT).show();
    }

}

在这里我们吐司出v所在Context对象和View对象以及他所属的布局。
2、修改我们的布局文件
首先新建一个variable引入这个类。在data字段中加入

<variable
    name="event"
    type="com.znke.hellodatabinding.ClickEvent"/>

其实,我们可以使用import直接导入这个类,值得注意的是,这个区别于javaimport关键字,java中这个是导入包,而这个是导入类。完整的data代码如下:

<data>
    <import type="com.znke.hellodatabinding.Person"/>
    <import type="com.znke.hellodatabinding.ClickEvent"/>
    <variable
        name="person"
        type="Person"/>
    <variable
        name="event"
        type="ClickEvent"/>
</data>

之后,我们在布局文件中加入一个Button,在onClick属性中引用这个类

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="测试"
    android:onClick="@{event.click}"/>

最后别忘记在Acticity中绑定!!!

...
    binding.setEvent(new ClickEvent());
...

运行正常如下:


quickstart
quickstart

5、Include对象传递

Databinding支持include对象传递,在A布局里面的对象可以传递到他include进来的布局,

  1. 在A布局里定义号自定义命名空间。xmlns:app="http://schemas.android.com/apk/res-auto"下面要用到。
  2. A布局里面的include标签
    <include layout="@layout/include_click"
        app:event="@{event}"/>
  1. B布局代码
    在B中也要引用一个传递过来的类,这个布局不用在Acticity中绑定。看过这个代码之后,你可能回想怎么不用merge优化呢,——暂时不支持
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="event"
            type="com.znke.hellodatabinding.ClickEvent"/>
    </data>

    <!-- 暂不支持merge标签 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="测试"
            android:onClick="@{event.click}"/>
    </LinearLayout>
</layout>

6、表达式符号

布局文件支持这些表达式,我直接引用谷歌文档
https://developer.android.com/tools/data-binding/guide.html

Mathematical  + - / * %
String  + 这个符号可能会引起引号冲突,需把文字放到资源文件
Logical  && ||
Binary & | ^
Unary + - ! ~
Shift >> >>> <<
Comparison == > < >= <=
instanceof
Grouping ()
Literals - character, String, numeric, null
Cast
Method calls
Field access
Array access []
Ternary operator ?:

7、绑定对象与视图,使他们能联动

通过更改对象,视图自动就会随之改变,这个功能实现View与model层逻辑代码的解耦和。
谷歌给出两种方法

  1. Observable Objects
    将你的POJO继承BaseObservable,这个类实现了Observable。可以实现POJO值改变,framework层会自动更新布局文件数据
private static class Person extends BaseObservable {
       private String name;
       private String age;
       @Bindable
       public String getName() {
           return name;
       }
       @Bindable
       public String getAge() {
           return age;
       }
       public void setName(String name) {
           this.name = name;
           notifyPropertyChanged(BR.name);
       }
       public void setAge(String age) {
           this.age = age;
           notifyPropertyChanged(BR.age);
       }
}
  1. ObservableFields
    其实他继承了BaseObservable这个类,在他的泛型中添上你的类型。同时
    ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble,ObservableParcelable
    也都是继承了BaseObservable。
public class Person {
        public ObservableField<String> name = new ObservableField<>();
        public ObservableInt age = new ObservableInt();
}

注:谷歌文档也给了一个Observable Collections,但我没试验成功,但是使用上面那个方法,是可以实现集合更改的。

通过上面的修改后,无论在那里改这个对象里面的值,相应的布局文件里面的引用都会随之改变。

8、抛弃你的findViewById()

有了Databinding再也不用谢冗长的findViewById()了,框架会为你自动生成的BR文件。
首先在我们的布局文件中,为我们两个TextView加上id,回到Acticity中的Binding对象,是不是多出了两个属性。

    binding.tvText1.setText("");
    binding.tvText2.setText("");

这样你就可以直接给他设置文本了,但是有一种更好的方法,直接binding.setVariable(com.znke.hellodatabinding.BR.person,new Person());就可以直接给布局文件中的变量赋值。

BR存储了布局中data标签中的variable,相当于R文件。

9、Attribute Setters(属性设置)

这东西就好像Button里面的onClick属性,然后给他在Acticity里面写一个对应的实现方法。他的强大之处就是它可以什么都向里面设置。不关是点击事件。他对于的实现方法只需要用一个注解声明就可以了,写在那里都可以,即使是一个没有使用的java文件。
通过一个Demo来说明,他有一个输入框,输入框输入文字,上面的TextView也会随之改变,这里用到了属性设置对象绑定
布局代码

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="输入内容"
        app:textwatcher="@{person}"/>

属性设置代码

public class BindingAdapter {

    private static final String TAG = BindingAdapter.class.getSimpleName();

    /**
     * 添加上这个注解,方法为静态无返回值,
     * 方法有两个参数,第一个是控件本身,第二个为传进来的对象
     * 注意这个方法会被调用多次,其中会有对象为空的情况。So...
     *
     * @param e      控件本身
     * @param person 传进来的对象
     */
    @android.databinding.BindingAdapter({"app:textwatcher"})
    public static void editTextWatcher(final EditText e,final Person person) {
        if (person != null) {
            e.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                }

                @Override
                public void afterTextChanged(Editable s) {
                    person.name.set(s.toString());
                    e.setSelection(s.length());
                }
            });
        }
    }
}

BindingAdapter生命周期所在
View所在ActivityonCreate方法之后。当然,自定义监听除外

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

推荐阅读更多精彩内容