使用单向数据绑定时,您可以为属性设置值,并设置一个对该属性中的更改作出反应的监听器:
<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 注解,如以下代码段所示:
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);
}
}
}
由于可绑定属性的 getter 方法名为 getRememberMe(),因此该属性对应的 setter 方法会自动使用名称 setRememberMe()。
如需详细了解如何使用 BaseObservable 和 @Bindable,请参阅使用可观测数据对象。
使用自定义特性的双向数据绑定
该平台为最常见的双向属性和更改监听器提供了双向数据绑定实现,您可以在应用中使用这些实现。如果您希望对自定义属性使用双向数据绑定,则需要使用 @InverseBindingAdapter 和 @InverseBindingMethod 注解。
例如,如果您想在名为 MyView 的自定义视图中对 "time" 属性启用双向数据绑定,请完成以下步骤:
使用
@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; } }使用
@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(); }
此时,数据绑定知道在数据发生更改时要执行的操作(它会调用带有 @BindingAdapter 注解的方法),以及在视图属性发生更改时要调用的方法(它会调用 InverseBindingListener)。但是,它不知道属性何时更改或如何更改。
为此,您需要在视图上设置监听器。它可以是与自定义视图关联的自定义监听器,也可以是通用事件,例如焦点丢失或文本更改。将 @BindingAdapter 注解添加到为属性更改设置监听器的方法中:
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.
}
该监听器包含一个 InverseBindingListener 参数。您可以使用 InverseBindingListener 告知数据绑定系统属性已更改。然后,系统可以开始调用使用 @InverseBindingAdapter 注释的方法。
实际上,此监听器包含一些重要的逻辑,包括单向数据绑定的监听器。如需查看示例,请参阅文本属性更改适配器 TextViewBindingAdapter。
转化者数量
如果绑定到 View 对象的变量在显示之前需要以某种方式进行格式设置、转换或更改,则可以使用 Converter 对象。
以显示日期的 EditText 对象为例:
<EditText
android:id="@+id/birth_date"
android:text="@={Converter.dateToString(viewmodel.birthDate)}"
/>
viewmodel.birthDate 属性包含 Long 类型的值,因此需要使用转换器进行格式设置。
由于使用的是双向表达式,因此还需要一个反向转换器,让库知道如何将用户提供的字符串转换回后备数据类型(在本例中为 Long)。为此,请将 @InverseMethod 注解添加到其中一个转换器,并让此注解引用逆转换器。以下代码段展示了此配置的示例:
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.
}
}
使用双向数据绑定的无限循环
使用双向数据绑定时,请注意不要引入无限循环。当用户更改属性时,系统会调用使用 @InverseBindingAdapter 注释的方法,并将值分配给后备属性。这反过来又会调用使用 @BindingAdapter 注释的方法,从而触发对使用 @InverseBindingAdapter 注释的方法的另一次调用,如此循环往复。
因此,请务必在通过 @BindingAdapter 注解的方法中比较新旧值,以打破可能出现的无限循环。
双向特性
当您使用下表中的属性时,该平台会为双向数据绑定提供内置支持。如需详细了解平台如何提供此支持,请参阅相应绑定适配器的实现:
| 类 | 特性 | 绑定适配器 |
|---|---|---|
AdapterView
|
android:selectedItemPositionandroid:selection |
AdapterViewBindingAdapter
|
CalendarView |
android:date |
CalendarViewBindingAdapter
|
CompoundButton |
android:checked
|
CompoundButtonBindingAdapter
|
DatePicker
|
android:yearandroid:monthandroid: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:hourandroid:minute |
TimePickerBindingAdapter
|
其他资源
如需详细了解数据绑定,请参阅下面列出的其他资源。
示例
Codelab
博文
为你推荐
- 注意:当 JavaScript 处于关闭状态时,系统会显示链接文字
- 使用可观察的数据对象
- 布局和绑定表达式
- 将布局视图绑定到架构组件