使用可观察数据对象

可观察性是指对象能够通知其他对象其数据发生变化的能力。数据绑定库可让您使对象、字段或集合可观察。

您可以将任何对象用于数据绑定,但修改对象不会自动导致界面更新。您可以使用数据绑定使您的数据对象在数据更改时能够通知其他对象(称为监听器)。可观察类有三种类型:字段集合对象

当这些可观察数据对象之一绑定到界面并且数据对象的属性发生变化时,界面会自动更新。

可观察字段

如果您的类只有少量属性,那么创建实现 Observable 接口的类可能不值得。在这种情况下,您可以使用泛型 Observable 类和以下特定于基本类型的类来使字段可观察

可观察字段是具有单个字段的自包含可观察对象。原始版本在访问操作期间避免了装箱和拆箱。要使用此机制,请在 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();

可观察集合

有些应用使用动态结构来保存数据。可观察集合允许通过使用键访问这些结构。ObservableArrayMap 类在键是引用类型(例如 String)时非常有用,如以下示例所示

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&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"/>

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&lt;Object&gt;"/>
</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 接口,以高效地注册和通知监听器。

生命周期感知对象

您的应用中的布局还可以绑定到数据绑定源,这些源会自动通知界面数据中的更改。这样,您的绑定就会感知生命周期,并且仅在界面在屏幕上可见时才触发。

数据绑定支持 StateFlowLiveData。有关在数据绑定中使用 LiveData 的更多信息,请参阅使用 LiveData 通知 UI 数据更改

使用 StateFlow

如果您的应用使用带有 协程 的 Kotlin,则可以将 StateFlow 对象用作数据绑定源。要将 StateFlow 对象与绑定类一起使用,请指定一个生命周期所有者来定义 StateFlow 对象的范围。以下示例在绑定类实例化后将 activity 指定为生命周期所有者

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 对象无缝协作。您可以按如下方式一起使用 StateFlowViewModel

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

每当用户名称值更改时,界面都会自动更新。

禁用 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

博文