Làm việc với đối tượng dữ liệu quan sát được

Khả năng quan sát là khả năng một đối tượng thông báo cho người khác về những thay đổi trong dữ liệu. Thư viện liên kết dữ liệu cho phép bạn quan sát các đối tượng, trường hoặc bộ sưu tập.

Bạn có thể sử dụng bất kỳ đối tượng nào để liên kết dữ liệu, nhưng việc sửa đổi đối tượng đó sẽ không tự động cập nhật giao diện người dùng. Bạn có thể sử dụng tính năng liên kết dữ liệu để cho phép các đối tượng dữ liệu thông báo cho các đối tượng khác (gọi là trình nghe) khi dữ liệu của các đối tượng đó thay đổi. Có 3 loại lớp có thể quan sát: trường, bộ sưu tậpđối tượng.

Khi một trong các đối tượng dữ liệu có thể quan sát này được liên kết với giao diện người dùng và một thuộc tính của đối tượng dữ liệu thay đổi, giao diện người dùng sẽ tự động cập nhật.

Các trường có thể quan sát

Nếu các lớp của bạn chỉ có một vài thuộc tính, thì có thể bạn không cần tạo các lớp triển khai giao diện Observable. Trong trường hợp này, bạn có thể sử dụng lớp Observable chung và các lớp cụ thể nguyên gốc sau đây để khiến các trường có thể quan sát được:

Các trường có thể quan sát là các đối tượng có thể quan sát độc lập, có một trường duy nhất. Các phiên bản gốc tránh việc đóng hộp và mở hộp trong các thao tác truy cập. Để sử dụng cơ chế này, hãy tạo một thuộc tính public final bằng ngôn ngữ lập trình Java hoặc thuộc tính chỉ có thể đọc trong Kotlin, như trong ví dụ sau:

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();
}

Để truy cập vào giá trị của trường, hãy dùng phương thức truy cập set()get() hoặc sử dụng cú pháp thuộc tính Kotlin:

Kotlin

user.firstName = "Google"
val age = user.age

Java

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

Bộ sưu tập có thể quan sát

Một số ứng dụng dùng cấu trúc động để lưu giữ dữ liệu. Các bộ sưu tập có thể quan sát được cho phép truy cập vào các cấu trúc này bằng cách sử dụng một khoá. Lớp ObservableArrayMap rất hữu ích khi khoá là loại tham chiếu, chẳng hạn như String, như minh hoạ trong ví dụ sau:

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);

Trong bố cục, bạn có thể tìm thấy bản đồ bằng cách sử dụng các khoá chuỗi, như trong ví dụ sau:

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

Lớp ObservableArrayList hữu ích khi khoá là một số nguyên, như sau:

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);

Trong bố cục, bạn có thể truy cập danh sách thông qua các chỉ mục, như trong ví dụ sau:

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

Vật thể quan sát được

Một lớp triển khai giao diện Observable cho phép đăng ký các trình nghe muốn nhận thông báo về các thay đổi thuộc tính từ đối tượng có thể quan sát.

Giao diện Observable có cơ chế để thêm và xoá trình nghe, nhưng bạn sẽ quyết định thời điểm gửi thông báo. Để giúp việc phát triển dễ dàng hơn, Thư viện liên kết dữ liệu cung cấp lớp BaseObservable, lớp này triển khai cơ chế đăng ký trình nghe. Lớp dữ liệu triển khai BaseObservable chịu trách nhiệm thông báo khi các thuộc tính thay đổi. Để làm điều này, hãy chỉ định một chú giải Bindable cho phương thức getter và gọi phương thức notifyPropertyChanged() trong phương thức setter, như trong ví dụ sau:

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);
    }
}

Tính năng liên kết dữ liệu tạo ra một lớp có tên BR trong gói mô-đun, lớp này chứa mã nhận dạng của các tài nguyên dùng để liên kết dữ liệu. Chú giải Bindable tạo một mục nhập trong tệp lớp BR trong quá trình biên dịch. Nếu không thể thay đổi lớp cơ sở cho các lớp dữ liệu, bạn có thể triển khai giao diện Observable bằng cách sử dụng đối tượng PropertyChangeRegistry để đăng ký và thông báo hiệu quả cho trình nghe.

Đối tượng nhận biết vòng đời

Các bố cục trong ứng dụng cũng có thể liên kết với các nguồn liên kết dữ liệu có chức năng tự động thông báo cho giao diện người dùng về các thay đổi trong dữ liệu. Bằng cách đó, các liên kết của bạn nhận biết được vòng đời và chỉ được kích hoạt khi giao diện người dùng hiển thị trên màn hình.

Tính năng liên kết dữ liệu hỗ trợ StateFlowLiveData. Để biết thêm thông tin về cách sử dụng LiveData trong liên kết dữ liệu, hãy xem bài viết Sử dụng LiveData để thông báo cho giao diện người dùng về các thay đổi về dữ liệu.

Sử dụng StateFlow

Nếu ứng dụng của bạn dùng Kotlin với coroutine, thì bạn có thể dùng các đối tượng StateFlow làm nguồn liên kết dữ liệu. Để sử dụng đối tượng StateFlow với lớp liên kết, hãy chỉ định chủ sở hữu vòng đời để xác định phạm vi của đối tượng StateFlow. Ví dụ sau đây chỉ định hoạt động làm chủ sở hữu vòng đời sau khi lớp liên kết được tạo thực thể:

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

Như đã mô tả trong bài viết Liên kết khung hiển thị bố cục với Thành phần kiến trúc, tính năng liên kết dữ liệu hoạt động liền mạch với các đối tượng ViewModel. Bạn có thể sử dụng StateFlowViewModel cùng nhau như sau:

class ScheduleViewModel : ViewModel() {

    private val _username = MutableStateFlow<String>("")
    val username: StateFlow<String> = _username

    init {
        viewModelScope.launch {
            _username.value = Repository.loadUserName()
        }
    }
}

Trong bố cục, hãy gán thuộc tính và phương thức của đối tượng ViewModel cho các khung hiển thị tương ứng bằng cách sử dụng biểu thức liên kết, như trong ví dụ sau:

<TextView
    android:id="@+id/name"
    android:text="@{viewmodel.username}" />

Giao diện người dùng tự động cập nhật bất cứ khi nào giá trị tên của người dùng thay đổi.

Tắt tính năng hỗ trợ StateFlow

Đối với các ứng dụng sử dụng Kotlin và AndroidX, tính năng hỗ trợ StateFlow sẽ tự động được đưa vào liên kết dữ liệu. Điều này có nghĩa là phần phụ thuộc coroutine sẽ tự động được đưa vào ứng dụng của bạn nếu chưa có phần phụ thuộc.

Bạn có thể chọn không sử dụng chức năng này bằng cách thêm đoạn mã sau vào tệp build.gradle:

Groovy

android {
    ...
    dataBinding {
        addKtx = false
    }
}

Kotlin

android {
    ...
    dataBinding {
        addKtx = false
    }
}

Ngoài ra, bạn có thể tắt StateFlow trên toàn cục trong dự án của mình bằng cách thêm dòng sau vào tệp gradle.properties:

Groovy

android.defaults.databinding.addKtx = false

Kotlin

android.defaults.databinding.addKtx = false

Tài nguyên khác

Để tìm hiểu thêm về liên kết dữ liệu, hãy xem các tài nguyên sau đây để biết thêm tài nguyên:

Mẫu

Lớp học lập trình

Bài đăng trên blog