关于 Data Binding 的基本使用在上一篇文章中已经做了总结,接下来会着重介绍下 Data Binding 库中个人认为最重要的两个特性:Data ObjectsAttribute Setters。前者是真正能让我们实现数据-UI双向绑定的关键;后者则为我们提供了自定义 UI 控件数据绑定的可能性。

当然,至于 Data Binding 其他的特性诸如自定义Binding Class命名Views with IDs(此特性可以完全取代Butterknife啦)等,查阅官方文档可以了。

Data Objects(数据对象)

之前介绍的基本使用中,我们定义的 model 类对象虽然能够绑定对应的 UI 并显示数据,但是修改了对象的属性并不会更新 UI。为此,Data Binding 提供了三种不同的数据变动通知机制: observable objectsobservable fieldsobservable collection

当以上的 observable 对象绑定在 UI 上,数据发生变化时,UI 就会同步更新。

1. observable objects

此种方法其实就是让我们定义的 model 类继承一个基类 BaseObservable ,这个类是 Observable (Data Binding 中的)接口的实现类,内部也就是基于观察者模式的一套添加/移除 listener 的机制。BaseObservable 帮我们实现了 listener 的注册,但是我们需要在 getter 使用 Bindable 注解,并在 setter 中调用方法去发通知。例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static class User extends BaseObservable {
private String firstName;
private String lastName;
@Bindable
public String getFirstName() {
return this.firstName;
}
@Bindable
public String getLastName() {
return this.lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
}

Bindable 注解会在编译时在 BR 类内生成一个元素(比如上面代码中的 BR.firstName )。

个人总结:如果一个 model 类的属性有很多,或者是想在原有项目中引入 Data Binding 的话,使用此方法的编写和改动的工作量还是有点繁琐。(不知道有没有开发者已经提供了一键生成的 AS 插件 😏)

2. observable fields

我们还可以使用 ObservableField 及它的派生比如 ObservableIntObservableBoolean 等作为 model 的数据类型。我们只要在数据类中创建一个 public final 域即可:

1
2
3
4
5
6
7
private static class User {
public final ObservableField<String> firstName =
new ObservableField<>();
public final ObservableField<String> lastName =
new ObservableField<>();
public final ObservableInt age = new ObservableInt();
}

然后要存取数据的话,只需要使用 ObservableField 中的 getset 方法:

1
2
user.firstName.set("Google");
int age = user.age.get();

个人总结:相比第一种方法,代码编写更方便省时,缺点就是:1、数据类的 field 如果很多的话,写起来还是麻烦;2、一般我们都会用到 FastJson 配合 Retrofit 来做 API 请求,结果直接返回给我们对应直接转化好的 model 类对象,所以不太可能直接运用在原本项目中的 model 类中。参考 google 的 todo-mvvm-databinding 中可以发现,原本的 model 类还是不动,每个页面都有一个 ViewModel 类,用于存放该页面中所有的数据对象,都是 ObservableField 相关的类型。

3. observable collections

顾名思义,就是 observable 容器类,个人认为也算是上面一种。

比如使用 ObservableArrayMap

1
2
3
4
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);

在 xml 中,可以用 String 类型的 key 来获取 map 中的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
<data>
<import type="android.databinding.ObservableMap"/>
<variable name="user" type="ObservableMap&lt;String, Object&gt;"/>
</data>

<TextView
android:text='@{user["lastName"]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user["age"])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

当 key 是 int 类型还可以使用 ObservableArrayList,使用的话和 ArrayList 没啥却别:

1
2
3
4
ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);

xml 中就是通过下标来获取数据,就不贴代码了 😁。


先写到这,下篇再总结Attribute Setters