Data Binding学习笔记——基本使用

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

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}"