Android DataBinding基本用法

Learning By Doing

一个Demo掌握DataBinding的基本用法

前言

DataBinding 是Google推出的一个支持库,它的作用是:通过layout文件绑定app逻辑和UI的更新,尽可能地减少编码工作。

说定义似乎有些隐晦,还是通过learning by doing的方式来学习吧。

这篇文章包括以下几方面的内容:

  • 通过layout来绑定app逻辑
  • layout里包含include标签的用法
  • 点击事件的处理
  • 使用Observablues动态更新UI
  • 使用ObervablueFields动态更新UI

我会按照上面列的顺序,一步步在Demo里面实现对应的功能

所有的源码都包含在这篇文章里,需要Demo的可以评论留言

由于是Learning By Doing,所以不会有理论的讲解,关于为什么是layout便签,为什么支持这样调用等问题,请去Android Developer 看官方文档,或者去Stack Overflow 提问

通过layout来绑定app逻辑

注意:

首先打开Andriod Studio,并创建一个新的项目,然后再正式开始我们的DataBinding之旅。

加入Databinding

在app/gradle文件中加入:

1
2
3
Databinding{
Eanbled = true
}

就可以使用DataBinding了,前提是你的Android Studio是2.1.3以上的版本(目前最新版已经是3.1.4了~)

编写Bean

这里我们用User类来演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class User {

private String name;
private String email;

public String getName() {
return name == null ? "" : name;
}

public void setName(String name) {
this.name = name;
}

public String getEmail() {
return email == null ? "" : email;
}

public void setEmail(String email) {
this.email = email;
}

}

Android Stuido: command/ctrl + n 快捷键 可以快速创建构造方法,gettet/setter方法等

编写layout文件

打开activity_main.xml 文件,把根目录改成layout,并且加入data 和 variable 标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/tools">

<data>
<variable
name="user"
type="com.blue.androidlearningcode.databinding.User"/>

</data>

<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" />

<TextView
android:id="@+id/email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.email}" />
</layout>
  • layout data variables的官方定义:

    The Data Binding Library automatically generates the classes required to bind the views in the layout with your data objects. The library provides features such as imports, variables, and includes that you can use in your layouts.

  • data:用于定义在DataBinding里面需要用到的数据对象(data objects)

  • variable:比data更小的层级,通常是class,我们这里就是刚刚写的User类
  • textview: 通过@{user.xxx}来绑定user里面的属性

在代码中绑定xml里面的控件

回到MainActivity.class文件中,现在我们需要做的就是把刚刚写的layout文件,和生成的DataBinding绑定起来。

首先,让我们愉快的 clean & rebuild project

为什么呢? 因为DataBinding需要在Build的过程中生成绑定类

ps:实际开发中,如果项目过大,可能Restart Android Studio比较快。。

OK,如果一切顺利的话,就开始写MainActivity的代码吧,在onCreate方法中:

1
2
3
4
5
6
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
user = new User();
user.setName("BlueLzy");
user.setEmail("bluehobert@gmail.com");

binding.setUser(user);
  • ActivityMainBinding:这货就是Build完生成出来的东西
  • binding.setUser():绑定对应的bean

好了,run一下,应该就能看到在两个TextView中分别出现了name和email的value了

layout里包含include标签的用法

上面的用法其实就是DataBinding最基本的用法,通过xml和class的绑定,减少我们在class里面编写的代码量。

但是理想很丰满,现实很骨感,项目中总是会有许多意想不到的需求,例如:我要在layout里面使用include标签,咋整?

如果直接把include标签加入到父布局,然后运行程序,你会发现是不行的,我们有些小细节要处理。

So,let‘s do it.

新建content_data_binding.xml

在layout文件夹下新建一个布局文件,用于存放我们需要用到的view

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android" >

<data>
<variable
name="user"
type="com.blue.androidlearningcode.databinding.User"/>
</data>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" />

<TextView
android:id="@+id/email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.email}" />

</LinearLayout>

</layout>

可以看到,其实我们就是把activity_main.xml的两个TextView搬到了这个新的layout中。

修改activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/tools">

<data>
<variable
name="user"
type="com.blue.androidlearningcode.databinding.User"/>

</data>

<include
android:id="@+id/content"
layout="@layout/content_data_binding"
bind:user="@{user}" />

</layout>

其实使用include标签要注意的地方就是:

  1. 父布局的include标签需要加上: bind:user=”@{user}” ,通过这行代码来关联bean和layout
  2. 子布局也需要加上layout,data,variable等标签

OK,再次运行程序,我们会发现效果和上面的一样,显示出来了name和email的值。

点击事件的处理

上面的Demo只是静态的,还无法对view的onClick,onLongClick 或者其他方法进行响应,那么接下来我们首先处理的就是onClick事件

修改MainActivity

创建MyClickHandlers内部类

在FAB点击的时候弹出Toast

1
2
3
4
5
6
public class MyClickHandlers {

public void onFabClicked(View view){
Toast.makeText(getApplicationContext(), "FAB clicked!", Toast.LENGTH_SHORT).show();
}
}

修改activity_main.xml

我们在这里使用FAB(FloatingActionButton)来演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/tools">

<data>
<variable
name="user"
type="com.blue.androidlearningcode.databinding.User"/>

<variable
name="handlers"
type="com.blue.androidlearningcode.DataBindingTestActivity.MyClickHandlers"/>
</data>

<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<include
android:id="@+id/content"
layout="@layout/content_data_binding"
bind:user="@{user}" />

<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="20dp"
app:srcCompat="@android:drawable/ic_dialog_info"
android:onClick="@{handlers::onFabClicked}"/>
</android.support.design.widget.CoordinatorLayout>

</layout>

绑定MyClickHandlers

又来到了clean & rebuild 时刻,在onCreate()里面进行绑定

1
2
MyClickHandlers handlers = new MyClickHandlers();
binding.content.setHandlers(handlers); // binding content layout click event
  • 为什么上面的User是binding.setUser(),而这里是binding.content.setHandlers()呢:

    这个问题很有趣,细心的童鞋应该是可以发现的,原因在xml的代码里

OK,let‘s run it!!!

Sep-09-201820-50-31.gif

我们虽然没有在代码里面重写onClickListener和onClick方法,但是通过DataBinding的方式还是成功实现了view的onClick(),至于上面的name和email的更新,就是下面要讲的了。

使用Observablues动态更新UI

推动人类进步的,其实是懒惰。为了能够少写两行代码,人类总是可以发明出各种新技术。例如:Observablues

Question:有没有办法在数据变化的时候让UI自动刷新呢?

答案当然是有的,let me show you:

修改User类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class User extends BaseObservable{

private String name;
private String email;

@Bindable
public String getName() {
return name == null ? "" : name;
}

public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}

@Bindable
public String getEmail() {
return email == null ? "" : email;
}

public void setEmail(String email) {
this.email = email;
notifyPropertyChanged(BR.email);
}

}
  • User继承BaseObservable
  • 每个getter()加上注解@Bindable
  • 每个setter()加上notifyPropertyChanged(BR.xxx); - BR在rebuild后自动生成

修改MainActivity

我们只需要改一个地方:onFabClicked()

1
2
3
4
5
public void onFabClicked(View view){
Toast.makeText(getApplicationContext(), "FAB clicked!", Toast.LENGTH_SHORT).show();
user.setName("BlueLzyzzz");
user.setEmail("blueblueblue@163.com");
}

我们并没有给textview设置text,而是给user的name和email重新赋值,看一下在FAB点击的时候UI会不会跟随data进行动态刷新。

run the project 。。。。。and 回头看上面的动图,哈哈哈~

使用ObervablueFields动态更新UI

其实上面已经把DataBinding的基本用法讲的差不多了,通过实践的方式一步步学习DataBinding,我觉得还是比较快速和容易上手的。

至于ObervablueFields,它其实也是为了能够减少代码量,当一个Bean没有那么多属性的时候,我们不需要写这么多的get和set方法,使用ObervablueFields只需要通过两行代码即可实现相同效果。

下面是Demo:

修改User类

加上age属性:

1
2
3
4
5
6
// 使用ObservableField
public static ObservableField<String> age = new ObservableField<>();

public static ObservableField<String> getAge() {
return age;
}

修改content_data_binding.xml

多加一个TextView

1
2
3
4
5
<TextView
android:id="@+id/age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.age}" />

修改MainActivity

修改onFabClicked()

1
2
3
4
5
6
public void onFabClicked(View view){
Toast.makeText(getApplicationContext(), "FAB clicked!", Toast.LENGTH_SHORT).show();
user.setName("BlueLzyzzz");
user.setEmail("blueblueblue@163.com");
User.age.set("20");
}

其实就是多加了一行,User.age.set(“20”); 因为age是静态变量,所以可以直接引用。

效果嘛。。还是回头看动图吧~~~

在实际项目中,通常一个API返回的Bean都会有十几个属性,多的可能有几十个,我们不可能一个个去写getter和setter还有@Bindable,这时候可以通过ObervablueFields来减少工作量,也可以通过插件来自动生成需要的代码。


本文结束啦感谢您的阅读