Data Binding 是 google 推出的布局与数据做双向绑定的库。它是一个 support library,可以在 Android 2.1 (API level 7+)以上的平台使用,同时 Android Plugin for Gradle 的版本必须是 1.5.0-alpha1 以上。

编译环境

build.gradle中添加:

1
2
3
4
5
6
android {
    ....
    dataBinding {
        enabled = true
    }
}

有一点要注意,如果 library 项目中使用了 data binding,app 项目必须也得在build.gradle中声明以上配置。

基本使用

这里分三部分来讲解:1、model 类;2、布局文件;3、activity/fragment

model 类的定义

定义一个 POJO(plain-old Java object),形如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class User {
   private final String firstName;
   private final String lastName;
   public User(String firstName, String lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
   }
   public String getFirstName() {
       return this.firstName;
   }
   public String getLastName() {
       return this.lastName;
   }
}

布局文件

使用一个名为layout的根节点编写我们以往的 layout 文件,在data节点内声明我们要绑定的数据,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>

我们可以看到,在data节点内的<variable name="user" type="com.example.User"/> 描述了此 layout 文件要使用的 model,在TextView的使用形如@{user.firstName} 来设置 text。

activity/fragment

  • 数据绑定

通常情况下,as 会根据我们刚才编写的 layout 文件自动生成一个 Binding class,如果 layout 文件为activity_main.xml,则生成的 class 就命名为ActivityMainBinding。然后我们需要在代码中使用这个类来做数据绑定:

1
2
3
4
5
6
7
8
9
@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
   //or
   //MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
   User user = new User("Test", "User");
   binding.setUser(user);
}

如果我们是在 ListView 或 RecyclerView 的 adapter 中要使用 data binding,如下使用:

1
2
3
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
//or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
  • 事件处理

Data Binding 提供了两种方式来做事件绑定和处理:Method ReferencesListener Bindings

这两种方式最主要的区别在于:Method References是当数据被绑定时就创建了对应的 listener,而Listener Bindings则是当事件发生时创建。

Method References

定义一个用来处理事件的类:

1
2
3
public class MyHandlers {
    public void onClickFriend(View view) { ... }
}

layout 文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="handlers" type="com.example.MyHandlers"/>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"
           android:onClick="@{handlers::onClickFriend}"/>
   </LinearLayout>
</layout>

此方式必须保证类中的方法签名和对应 listener 的签名保持一致,否则在编译期间会报错。

Listener Bindings

此种方式和method references类似,也是定义一个类来处理事件,区别是在 xml 中使用 lambda 表达式来声明,而且只需要类的返回类型和 listener 一致即可。

1
2
3
public class Presenter {
    public void onSaveClick(View view, Task task){}
}
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="utf-8"?>
  <layout xmlns:android="http://schemas.android.com/apk/res/android">
      <data>
          <variable name="task" type="com.android.example.Task" />
          <variable name="presenter" type="com.android.example.Presenter" />
      </data>
      <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
          <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
          android:onClick="@{(v) -> presenter.onSaveClick(v, task)}" />
      </LinearLayout>
  </layout>

如果要在表达式中使用断言,我们可以使用void作为一个符号:

1
android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"

参考文章:
http://yanghui.name/blog/2016/02/17/data-binding-guide/ > https://developer.android.google.cn/topic/libraries/data-binding/index.html