Liên kết dữ liệu hai chiều

Khi sử dụng tính năng liên kết dữ liệu một chiều, bạn có thể đặt giá trị trên một thuộc tính và thiết lập trình nghe phản ứng với thay đổi trong thuộc tính đó:

<CheckBox
    android:id="@+id/rememberMeCheckBox"
    android:checked="@{viewmodel.rememberMe}"
    android:onCheckedChanged="@{viewmodel.rememberMeChanged}"
/>

Liên kết dữ liệu hai chiều cung cấp lối tắt cho quy trình này:

<CheckBox
    android:id="@+id/rememberMeCheckBox"
    android:checked="@={viewmodel.rememberMe}"
/>

Ký hiệu @={}, quan trọng là ký hiệu "=", sẽ nhận các thay đổi về dữ liệu đối với thuộc tính và theo dõi thông tin cập nhật của người dùng cùng lúc.

Để thích ứng với các thay đổi trong dữ liệu sao lưu, bạn có thể triển khai biến bố cục của Observable, thường là BaseObservable và sử dụng chú giải @Bindable, như minh hoạ trong đoạn mã sau:

Kotlin

class LoginViewModel : BaseObservable {
    // val data = ...

    @Bindable
    fun getRememberMe(): Boolean {
        return data.rememberMe
    }

    fun setRememberMe(value: Boolean) {
        // Avoids infinite loops.
        if (data.rememberMe != value) {
            data.rememberMe = value

            // React to the change.
            saveData()

            // Notify observers of a new value.
            notifyPropertyChanged(BR.remember_me)
        }
    }
}

Java

public class LoginViewModel extends BaseObservable {
    // private Model data = ...

    @Bindable
    public Boolean getRememberMe() {
        return data.rememberMe;
    }

    public void setRememberMe(Boolean value) {
        // Avoids infinite loops.
        if (data.rememberMe != value) {
            data.rememberMe = value;

            // React to the change.
            saveData();

            // Notify observers of a new value.
            notifyPropertyChanged(BR.remember_me);
        }
    }
}

Vì phương thức getter của thuộc tính có thể liên kết được gọi là getRememberMe(), nên phương thức setter tương ứng của thuộc tính sẽ tự động sử dụng tên setRememberMe().

Để biết thêm thông tin về cách sử dụng BaseObservable@Bindable, hãy xem bài viết Làm việc với các đối tượng dữ liệu có thể quan sát.

Liên kết dữ liệu hai chiều bằng cách sử dụng các thuộc tính tuỳ chỉnh

Nền tảng này cung cấp các cách triển khai liên kết dữ liệu hai chiều cho các thuộc tính hai chiều phổ biến nhất và các trình nghe thay đổi mà bạn có thể sử dụng như một phần của ứng dụng. Nếu muốn sử dụng liên kết dữ liệu hai chiều với các thuộc tính tuỳ chỉnh, bạn cần sử dụng các chú giải @InverseBindingAdapter@InverseBindingMethod.

Ví dụ: nếu bạn muốn bật tính năng liên kết dữ liệu hai chiều trên thuộc tính "time" trong khung hiển thị tuỳ chỉnh có tên là MyView, hãy hoàn tất các bước sau:

  1. Chú giải phương thức đặt giá trị ban đầu và cập nhật khi giá trị đó thay đổi bằng cách sử dụng @BindingAdapter:

    Kotlin

    @BindingAdapter("time")
    @JvmStatic fun setTime(view: MyView, newValue: Time) {
        // Important to break potential infinite loops.
        if (view.time != newValue) {
            view.time = newValue
        }
    }

    Java

    @BindingAdapter("time")
    public static void setTime(MyView view, Time newValue) {
        // Important to break potential infinite loops.
        if (view.time != newValue) {
            view.time = newValue;
        }
    }
  2. Chú thích phương thức đọc giá trị từ khung hiển thị bằng cách sử dụng @InverseBindingAdapter:

    Kotlin

    @InverseBindingAdapter("time")
    @JvmStatic fun getTime(view: MyView) : Time {
        return view.getTime()
    }

    Java

    @InverseBindingAdapter("time")
    public static Time getTime(MyView view) {
        return view.getTime();
    }

Tại thời điểm này, tính năng liên kết dữ liệu biết việc cần làm khi dữ liệu thay đổi (gọi phương thức được chú thích bằng @BindingAdapter) và nội dung cần gọi khi thuộc tính khung hiển thị thay đổi (gọi InverseBindingListener). Tuy nhiên, thuộc tính này không biết khi nào hoặc cách thuộc tính này thay đổi.

Để làm được việc đó, bạn cần thiết lập một trình nghe trên khung hiển thị. Đó có thể là một trình nghe tuỳ chỉnh liên kết với khung hiển thị tuỳ chỉnh của bạn hoặc có thể là một sự kiện chung, chẳng hạn như mất tiêu điểm hoặc thay đổi văn bản. Thêm chú giải @BindingAdapter vào phương thức sẽ thiết lập trình nghe để biết các thay đổi trên thuộc tính:

Kotlin

@BindingAdapter("app:timeAttrChanged")
@JvmStatic fun setListeners(
        view: MyView,
        attrChange: InverseBindingListener
) {
    // Set a listener for click, focus, touch, etc.
}

Java

@BindingAdapter("app:timeAttrChanged")
public static void setListeners(
        MyView view, final InverseBindingListener attrChange) {
    // Set a listener for click, focus, touch, etc.
}

Trình nghe có tham số là InverseBindingListener. Bạn dùng InverseBindingListener để thông báo cho hệ thống liên kết dữ liệu biết thuộc tính này đã thay đổi. Sau đó, hệ thống có thể bắt đầu gọi phương thức được chú giải bằng @InverseBindingAdapter, v.v.

Trên thực tế, trình nghe này bao gồm một số logic không quan trọng, bao gồm cả trình nghe để liên kết dữ liệu một chiều. Ví dụ: xem bộ chuyển đổi cho thay đổi thuộc tính văn bản, TextViewBindingAdapter.

Người chuyển đổi

Nếu biến liên kết với đối tượng View cần được định dạng, dịch hoặc thay đổi theo cách nào đó trước khi hiển thị, thì bạn có thể sử dụng đối tượng Converter.

Ví dụ: lấy đối tượng EditText cho thấy ngày:

<EditText
    android:id="@+id/birth_date"
    android:text="@={Converter.dateToString(viewmodel.birthDate)}"
/>

Thuộc tính viewmodel.birthDate chứa giá trị thuộc loại Long, vì vậy, bạn cần định dạng thuộc tính này bằng cách sử dụng trình chuyển đổi.

Vì biểu thức hai chiều đang được sử dụng, nên cũng cần có trình chuyển đổi đảo ngược để cho thư viện biết cách chuyển đổi chuỗi do người dùng cung cấp trở về loại dữ liệu sao lưu, trong trường hợp này là Long. Quá trình này được thực hiện bằng cách thêm chú thích @InverseMethod vào một trong các trình chuyển đổi và để chú thích này tham chiếu đến trình chuyển đổi nghịch đảo. Ví dụ về cấu hình này xuất hiện trong đoạn mã sau:

Kotlin

object Converter {
    @InverseMethod("stringToDate")
    @JvmStatic fun dateToString(
        view: EditText, oldValue: Long,
        value: Long
    ): String {
        // Converts long to String.
    }

    @JvmStatic fun stringToDate(
        view: EditText, oldValue: String,
        value: String
    ): Long {
        // Converts String to long.
    }
}

Java

public class Converter {
    @InverseMethod("stringToDate")
    public static String dateToString(EditText view, long oldValue,
            long value) {
        // Converts long to String.
    }

    public static long stringToDate(EditText view, String oldValue,
            String value) {
        // Converts String to long.
    }
}

Vòng lặp vô hạn sử dụng liên kết dữ liệu hai chiều

Hãy cẩn thận để không tạo ra vòng lặp vô hạn khi sử dụng liên kết dữ liệu hai chiều. Khi người dùng thay đổi một thuộc tính, phương thức được chú giải bằng @InverseBindingAdapter sẽ được gọi và giá trị này được gán cho thuộc tính dự phòng. Đổi lại, điều này sẽ gọi phương thức được chú thích bằng @BindingAdapter, kích hoạt một lệnh gọi khác đến phương thức được chú thích bằng @InverseBindingAdapter, v.v.

Vì lý do này, bạn cần phải phá vỡ các vòng lặp vô hạn có thể xảy ra bằng cách so sánh các giá trị mới và cũ trong các phương thức được chú giải bằng @BindingAdapter.

Thuộc tính hai chiều

Nền tảng này cung cấp tính năng hỗ trợ tích hợp cho việc liên kết dữ liệu hai chiều khi bạn sử dụng các thuộc tính trong bảng sau. Để biết thông tin chi tiết về cách nền tảng cung cấp tính năng hỗ trợ này, hãy xem cách triển khai cho các bộ chuyển đổi liên kết tương ứng:

Lớp (Các) thuộc tính Bộ chuyển đổi liên kết
AdapterView android:selectedItemPosition
android:selection
AdapterViewBindingAdapter
CalendarView android:date CalendarViewBindingAdapter
CompoundButton android:checked CompoundButtonBindingAdapter
DatePicker android:year
android:month
android:day
DatePickerBindingAdapter
NumberPicker android:value NumberPickerBindingAdapter
RadioButton android:checkedButton RadioGroupBindingAdapter
RatingBar android:rating RatingBarBindingAdapter
SeekBar android:progress SeekBarBindingAdapter
TabHost android:currentTab TabHostBindingAdapter
TextView android:text TextViewBindingAdapter
TimePicker android:hour
android:minute
TimePickerBindingAdapter

Tài nguyên khác

Để tìm hiểu thêm về tính năng liên kết dữ liệu, hãy tham khảo thêm các tài nguyên sau đây.

Mẫu

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

Bài đăng trên blog