可观察性是指对象能够通知其他对象其数据更改的能力。数据绑定库允许您使对象、字段或集合可观察。
您可以使用任何对象进行数据绑定,但修改对象不会自动导致 UI 更新。您可以使用数据绑定赋予您的数据对象通知其他对象(称为侦听器)其数据更改的能力。有三种类型的可观察类:字段、集合 和 对象。
当这些可观察数据对象之一绑定到 UI 并且数据对象的属性发生更改时,UI 会自动更新。
可观察字段
如果您的类只有几个属性,那么创建实现 Observable
接口的类可能不值得。在这种情况下,您可以使用通用 Observable
类以及以下特定于原语的类来使字段可观察
ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable
可观察字段是自包含的可观察对象,它们具有单个字段。原始版本避免在访问操作期间进行装箱和拆箱。要使用此机制,请在 Java 编程语言中创建一个 public final
属性,或在 Kotlin 中创建一个只读属性,如下例所示
Kotlin
class User { val firstName = ObservableField<String>() val lastName = ObservableField<String>() val age = ObservableInt() }
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(); }
要访问字段值,请使用 set()
和 get()
访问器方法,或使用 Kotlin 属性语法
Kotlin
user.firstName = "Google" val age = user.age
Java
user.firstName.set("Google"); int age = user.age.get();
可观察集合
某些应用使用动态结构来保存数据。可观察集合允许通过使用键访问这些结构。当键是引用类型(例如 String
)时,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
类很有用,如下所示
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
接口有一种机制来添加和删除侦听器,但您决定何时发送通知。为了简化开发,数据绑定库提供了 BaseObservable
类,该类实现了侦听器注册机制。实现 BaseObservable
的数据类负责在属性更改时发出通知。为此,请为 getter 分配 Bindable
注解,并在 setter 中调用 notifyPropertyChanged()
方法,如下例所示
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) } }
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); } }
数据绑定在模块包中生成一个名为 BR
的类,其中包含用于数据绑定的资源的 ID。Bindable
注解在编译期间在 BR
类文件中生成一个条目。如果数据类的基类无法更改,则可以使用 PropertyChangeRegistry
对象来有效地注册和通知侦听器,从而实现 Observable
接口。
生命周期感知对象
应用程序中的布局还可以绑定到数据绑定源,这些源会自动通知 UI 数据的变化。这样,您的绑定就会感知生命周期,并且仅在 UI 在屏幕上可见时才会触发。
数据绑定支持StateFlow
和 LiveData
。有关在数据绑定中使用LiveData
的更多信息,请参阅使用 LiveData 通知 UI 数据更改。
使用 StateFlow
如果您的应用使用 Kotlin 和协程,则可以使用StateFlow
对象作为数据绑定源。要将StateFlow
对象与您的绑定类一起使用,请指定一个生命周期所有者来定义StateFlow
对象的作用域。以下示例在绑定类实例化后指定活动作为生命周期所有者
class ViewModelActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Inflate view and obtain an instance of the binding class.
val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)
// Specify the current activity as the lifecycle owner.
binding.lifecycleOwner = this
}
}
如将布局视图绑定到架构组件中所述,数据绑定与ViewModel
对象无缝协作。您可以按如下方式将StateFlow
和ViewModel
结合使用
class ScheduleViewModel : ViewModel() {
private val _username = MutableStateFlow<String>("")
val username: StateFlow<String> = _username
init {
viewModelScope.launch {
_username.value = Repository.loadUserName()
}
}
}
在您的布局中,使用绑定表达式将ViewModel
对象的属性和方法分配给相应的视图,如以下示例所示
<TextView
android:id="@+id/name"
android:text="@{viewmodel.username}" />
每当用户姓名值更改时,UI 都会自动更新。
禁用 StateFlow 支持
对于使用 Kotlin 和 AndroidX 的应用,数据绑定会自动包含StateFlow
支持。这意味着如果您的应用中尚不存在协程依赖项,则会自动将其包含在内。
您可以通过在build.gradle
文件中添加以下内容来选择退出此功能
Groovy
android { ... dataBinding { addKtx = false } }
Kotlin
android { ... dataBinding { addKtx = false } }
或者,您可以通过在gradle.properties
文件中添加以下行来全局禁用项目中的StateFlow
Groovy
android.defaults.databinding.addKtx = false
Kotlin
android.defaults.databinding.addKtx = false
其他资源
要了解有关数据绑定的更多信息,请参阅以下其他资源
示例
Codelabs
博文
为您推荐
- 注意:当 JavaScript 关闭时显示链接文本
- ViewModel 的 Saved State 模块
- 将布局视图绑定到架构组件
- 分页库概述