Jetpack学习6—双向数据绑定

[TOC]

Jetpack学习6—双向数据绑定

使用单向数据绑定,您可以在属性上设置一个值,并设置一个侦听器来响应该属性中的更改:

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

因为可绑定属性的getter方法称为getmemorberme(),所以属性对应的setter方法会自动使用setmemorberme()这个名称。

有关使用BaseObservable和的更多信息@Bindable,请参阅使用可观察数据对象

使用自定义属性进行双向数据绑定

该平台为最常见的双向属性和change listeners提供了双向数据绑定实现,您可以将其作为应用程序的一部分使用。如果您想使用带有自定义属性的双向数据绑定,您需要使用@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();
}

此时,数据绑定知道数据更改时要做什么(它调用带注释的方法 @BindingAdapter)以及视图属性更改时调用什么(它调用 InverseBindingListener)。但是,它不知道属性何时或如何更改。

为此,您需要在视图上设置一个侦听器。它可以是与自定义视图关联的自定义侦听器,也可以是通用事件,例如失去焦点或文本更改。将@BindingAdapter注释添加到为该属性的更改设置侦听器的方法上:

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

监听器包括InverseBindingListener作为参数。使用 InverseBindingListener来告诉数据绑定系统该属性已更改。然后,系统可以开始调用使用注释的方法 @InverseBindingAdapter,依此类推。

注意:每个双向绑定都会生成一个合成事件属性。此属性与基本属性具有相同的名称,但它包含后缀 "AttrChanged"。合成事件属性允许库创建使用@BindingAdapter标注的方法,以将事件侦听器关联到视图的适当实例。

转换器

如果绑定到View对象的变量需要在显示之前以某种方式进行格式化,翻译或更改,则可以使用Converter对象。

以显示日期的EditText对象为例:

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

viewmodel.birthDate属性包含一个Long类型的值,因此需要使用转换器对其进行格式化。

因为使用的是双向表达式,所以还需要一个反向转换器,让库知道如何将用户提供的字符串转换回支持的数据类型(在本例中为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.
    }
}

使用双向数据绑定的无限循环

在使用双向数据绑定时,小心不要引入无限循环。当用户更改属性时,将调用使用@InverseBindingAdapter注释的方法,并将该值分配给支持属性。反过来,这会调用使用@BindingAdapter注释的方法,这会触发对使用@InverseBindingAdapter注释的方法的另一个调用,以此类推。

因此,通过比较使用@BindingAdapter标注的方法中的新值和旧值来打破可能的无限循环非常重要。

双向属性

当您使用下表中的属性时,该平台提供了对双向数据绑定的内置支持。有关平台如何提供这种支持的详细信息,请参见相应绑定适配器的实现:

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

其他资源

GitHub上的 TwoWaySample提供了本页讨论的概念的双向示例。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容