前言
使用單向數據綁定可以在屬性上設置數值,並可設定對該屬性的變化作出反應的監聽器。如下
<CheckBox
android:id="@+id/rememberMeCheckBox"
android:checked="@{viewmodel.rememberMe}"
android:onCheckedChanged="@{viewmodel.rememberMeChanged}"
/>
雙向數據綁定提供了此過程的捷徑。如下
<CheckBox
android:id="@+id/rememberMeCheckBox"
android:checked="@={viewmodel.rememberMe}"
/>
注意在 @={} 表示法中的 = 符號表示了同時接受資料變化以及監聽更新。
為了對數據的變化做出反應,可以讓佈局變量成為 Observable 的實現,通常是 BaseObservable,並使用 @Bindable 註釋,如下
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);
}
}
}
由於 bindable 屬性的 getter 方法稱為 getRememberMe(),因此屬性的相應 setter 方法會自動使用名稱 setRememberMe()。
關於使用 BaseObservable 和 @Bindable 的更多訊息,參考 Work with observable data objects.
Two-way data binding using custom attributes
該平台為最常見的雙向屬性和監聽器提供雙向數據綁定的實現,使用者可以將當作應用程序的一部分。
若使用者想在自定義屬性上使用雙向資料綁定則必須了解如何使用 @InverseBindingAdapter 和 @InverseBindingMethod 註解。
例如,如果要在名稱為 MyView 的自定義視圖中對 "time" 屬性啟用雙向數據綁定,必須完成以下步驟
1.註釋設置初始值的方法,並在使用 @BindingAdapter 更改時進行更新
@BindingAdapter("time")
public static void setTime(MyView view, Time newValue) {
// Important to break potential infinite loops.
if (view.time != newValue) {
view.time = newValue;
}
}
2.使用 @InverseBindingAdapter 註釋從視圖中讀取數值的方法
@InverseBindingAdapter("time")
public static Time getTime(MyView view) {
return view.getTime();
}
此時,data binding library 知道數據變化時要執行的操作(呼叫使用 @BindingAdapter 註釋的方法)以及視圖屬性變化時調用的內容(它呼叫 InverseBindingListener)。
為此,需要在視圖上設置一個監聽器。它可以是與自定義視圖關聯的自定義監聽器,也可以是通用事件,例如失去焦點或文本更改。
將 @BindingAdapter 註釋添加到為該屬性的變化設置監聽器的方法,如下
@BindingAdapter("app:timeAttrChanged")
public static void setListeners(
MyView view, final InverseBindingListener attrChange) {
// Set a listener for click, focus, touch, etc.
}
這個 Listener 包含了 InverseBindingListener 作為參數,可以使用 InverseBindingListener 告知 data binding library 該屬性已更改。接著,系統可以開始使用 @InverseBindingAdapter 呼叫註釋方法,依此類推。
注意每個雙向綁定都會生成一個合成事件屬性( synthetic event attribute)。此屬性與基本屬性具有相同的名稱,但具有後綴 "AttrChanged"。
合成事件屬性允許 data binding library 建立使用 @BindingAdapter 註釋的方法,以將事件監聽器連結到 View 的相應實體。
在實作中,該監聽器包括一些特殊的邏輯,包括用於單向數據綁定的監聽器。相關範例,參考TextViewBindingAdapter。
Converters
如果綁定到 View 對象的變數需要在顯示之前進行格式化,轉換或更改,則可以使用 Converter 對象。
例如,使用顯示日期的 EditText 對象
<EditText
android:id="@+id/birth_date"
android:text="@={Converter.dateToString(viewmodel.birthDate)}"
/>
viewmodel.birthDate 屬性包含 Long 類型的值,因此需要使用轉換器對其進行格式化。
因為使用雙向表達式,所以還需要一個反向轉換器(inverse converter)讓 data binding library 知道如何將字符串轉換回數據類型,在本例中為 Long。
此過程通過將 @InverseMethod 註釋添加到其中一個轉換器並使此註釋引用反向轉換器來完成。如下
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.
}
}
Infinite loops using two-way data binding
使用雙向數據綁定時,小心不要引入無限迴圈。
當用戶更改屬性時,將呼叫使用 @InverseBindingAdapter 註釋的方法,並將數值分配給 屬性。反過來,這將呼叫使用 @BindingAdapter 註釋的方法,這將觸發對使用 @InverseBindingAdapter 註釋的方法的另一個調用,依此類推。
因此,通過比較使用 @BindingAdapter 註釋的方法中的新値和舊值來打破可能的無限循環非常重要。
Two-way attributes
下表為平台預設的雙向綁定屬性表。
Class | Attribute(s) | Binding adapter | |||
---|---|---|---|---|---|
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 |
Orignal From: Two-way data binding (雙向數據綁定)