官方英文文档:https://developer.android.google.cn/topic/libraries/data-binding/observability
一、介绍
观察能力是指一个对象可以通知别人它的数据已经发生改变的能力。DataBinding
库允许你让你的对象、字段、集合具备观察能力。
普通对象可以用于DataBinding
,但是它们不会自动通知UI
它们发生改变了. DataBinding
可以赋予对象在数据改变时通知其他对象的能力 。
二、可观察字段(Observable Fields
)
当对象只有少量有效字段时,就没有必要创建一个实现Observable
接口的类了,对于这种情况,可以使用以下专用类来让字段具备观察能力。
ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable
可观察对象只有单个字段,基本类型版本在访问时可以避免自动装箱和自动拆箱,而要使用这一机制,可以如下创建public final
的Java
属性,或者创建只读read-only
的Kotlin
属性
// java
private static class User {
public final ObservableField<String> firstName = new ObservableField<>();
public final ObservableField<String> lastName = new ObservableField<>();
public final ObservableInt age = new ObservableInt();
}
// kotlin
class User {
val firstName = ObservableField<String>()
val lastName = ObservableField<String>()
val age = ObservableInt()
}
通过set
、get
方法刚问字段值:
// kotlin
user.firstName = "Google"
val age = user.age
// java
user.firstName.set("Google");
int age = user.age.get();
Note: 在Android studio 3.1
及以上版本中可以通过使用LiveData
来替换可观察字段,并且使用LiveData
可以带来额外的好处,具体看 这里.
三、可观察集合
一些应用需要使用动态数据结构来来存储数据,可观察集合允许通过key
来访问这些数据结构,如 ObservableArrayMap
.
// Kotlin
ObservableArrayMap<String, Any>().apply {
put("firstName", "Google")
put("lastName", "Inc.")
put("age", 17)
}
// Java
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);
而在布局中的使用方法如下示例:
<data>
<import type="android.databinding.ObservableMap"/>
<variable name="user" type="ObservableMap<String, Object>"/>
</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"/>
ObservableArrayList
在key
为整型数据时非常有用,如下:
//Kotlin
ObservableArrayList<Any>().apply {
add("Google")
add("Inc.")
add(17)
}
// java
ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);
对用在布局中可以通过索引来访问这个列表的数据,如下:
<data>
<import type="android.databinding.ObservableList"/>
<import type="com.example.my.app.Fields"/>
<variable name="user" type="ObservableList<Object>"/>
</data>
…
<TextView
android:text='@{user[Fields.LAST_NAME]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
四、可观察对象
实现了Observable
接口的类允许注册的监听器接收到它的字段数据发生改变的通知。
Observable
接口包含注册和移除监听器的机制,但是我们需要决定什么是时候发送通知,为了方便开发,Databinding
库提供了BaseObservable
类来实现这个监听器注册机制。继承了BaseObservable
的类负责在对象属性改变时发送通知,当给get
方法加上@Bindable
注解,且在set
方法中调用notifyPropertyChanged
方法时,这个流程就完成了,如下示例:
// Java
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);
}
}
// Kotlin
class User : BaseObservable() {
@get:Bindable
var firstName: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.firstName)
}
@get:Bindable
var lastName: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.lastName)
}
}
Data Binding
会在模块包生成一个叫做BR
的类,它包含了用于数据绑定的资源ID
,@Bindable
注解则会在编译时在BR
中生成一个entry
。如果数据类仍不能改变,那么可以通过PropertyChangeRegistry
对象注册和高效地通知监听器。
关于 Bindable
@Bindable
必须作为get
方法的注解,如下示例,注意到@Bindable({"firstName", "lastName"}}
, 这里可以绑定多个字段,而在这些字段中,当有一个字段被更新后,与之相关联的字段(如这里的name
,它依赖于firstName
和lastName
)都会被视作垃圾数据而被更新。但是这并不意味会onPropertyChanged(Observable, int)
会接收到因为BR.name
变成垃圾数据而触发的通知,当且仅当绑定表达式(binding expressions
)中包含name
字段的情况才会被视作垃圾数据并更新。
@Bindable
public void getFirstName() { return this.firstName; }
@Bindable
public void getLastName() { return this.lastName; }
@Bindable({"firstName", "lastName"}}
public void getName() { return this.firstName + ' ' + this.lastName; }
网友评论