Jetpack學(xué)習(xí)3--使用可觀察的對(duì)象&生成綁定類(lèi)

[TOC]

Jetpack學(xué)習(xí)3--使用可觀察的對(duì)象&生成綁定類(lèi)

使用可觀察的對(duì)象

可觀察性是指對(duì)象通知其他人數(shù)據(jù)變化的能力硅急。數(shù)據(jù)綁定庫(kù)允許您使對(duì)象,字段或集合可觀察萨西。

任何普通的舊對(duì)象都可以用于數(shù)據(jù)綁定妄壶,但是修改對(duì)象不會(huì)自動(dòng)導(dǎo)致UI更新霞扬。數(shù)據(jù)綁定可用于使數(shù)據(jù)對(duì)象能夠在數(shù)據(jù)發(fā)生更改時(shí)通知其他對(duì)象佑笋,即偵聽(tīng)器翼闹。有三種不同類(lèi)型的可觀察類(lèi):objects, fields, and collections.

當(dāng)其中一個(gè)可觀察數(shù)據(jù)對(duì)象綁定到UI并且數(shù)據(jù)對(duì)象的屬性發(fā)生更改時(shí),UI將自動(dòng)更新蒋纬。

可觀察的字段

創(chuàng)建實(shí)現(xiàn)Observable接口的類(lèi)涉及到一些工作猎荠,如果類(lèi)只有幾個(gè)屬性,那么這些工作就不值得了蜀备。在這種情況下关摇,您可以使用泛型Observable類(lèi)和以下原始特定類(lèi)來(lái)使字段可觀察:

可觀察字段是具有單個(gè)字段的自包含可觀察對(duì)象。原始版本在訪問(wèn)操作期間避免裝箱和解箱琼掠。要使用這種機(jī)制,請(qǐng)?jiān)贘ava編程語(yǔ)言中創(chuàng)建一個(gè)public final屬性停撞,或者在Kotlin中創(chuàng)建一個(gè)只讀屬性瓷蛙,如下面的示例所示:

private static class User {
    public final ObservableField<String> firstName = new ObservableField<>();
    public final ObservableField<String> lastName = new ObservableField<>();
    public final ObservableInt age = new ObservableInt();
}

要訪問(wèn)字段值,使用set()和get()訪問(wèn)器方法戈毒,如下所示:

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

注意:Android Studio 3.1及更高版本允許您使用LiveData對(duì)象替換可觀察字段艰猬,這為您的應(yīng)用提供了額外的好處。有關(guān)更多信息埋市,請(qǐng)參閱使用LiveData通知UI有關(guān)數(shù)據(jù)更改的信息冠桃。

可觀察的集合

一些應(yīng)用程序使用動(dòng)態(tài)結(jié)構(gòu)來(lái)保存數(shù)據(jù)〉勒可觀察集合允許使用密鑰訪問(wèn)這些結(jié)構(gòu)食听。如果鍵是引用類(lèi)型,比如字符串污茵,ObservableArrayMap類(lèi)非常有用樱报,如下面的例子所示:

ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);

在布局中,可以使用key使用map中的數(shù)據(jù)泞当,如下:

<data>
    <import type="android.databinding.ObservableMap"/>
    <variable name="user" type="ObservableMap<String, Object>"/>
</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"/>

當(dāng)key是int時(shí)可以使用ObservableArrayList迹蛤,如下:

ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);

在布局中,可以通過(guò)索引訪問(wèn)列表,如以下示例所示:

<data>
    <import type="android.databinding.ObservableList"/>
    <import type="com.example.my.app.Fields"/>
    <variable name="user" type="ObservableList<Object>"/>
</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"/>

可觀察對(duì)象

實(shí)現(xiàn)Observable接口的類(lèi)可以注冊(cè)監(jiān)聽(tīng)器盗飒,當(dāng)可觀察對(duì)象屬性改變時(shí)可以通知它嚷量。

Observable接口具有添加和刪除偵聽(tīng)器的機(jī)制,但是您必須決定何時(shí)發(fā)送通知逆趣。為了簡(jiǎn)化開(kāi)發(fā)蝶溶,數(shù)據(jù)綁定庫(kù)提供了BaseObservable類(lèi),該類(lèi)實(shí)現(xiàn)偵聽(tīng)器注冊(cè)機(jī)制汗贫。實(shí)現(xiàn)BaseObservable的數(shù)據(jù)類(lèi)負(fù)責(zé)在屬性發(fā)生變化時(shí)發(fā)出通知身坐。這是通過(guò)為getter分配一個(gè)Bindable注解,并在setter中調(diào)用notifyPropertyChanged()方法來(lái)實(shí)現(xiàn)的落包,如下面的示例所示:

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

數(shù)據(jù)綁定在模塊包中生成一個(gè)名為BR的類(lèi)部蛇,該類(lèi)包含用于數(shù)據(jù)綁定的資源的id。Bindable注解在編譯期間在BR類(lèi)文件中生成一個(gè)條目咐蝇。如果不能更改數(shù)據(jù)類(lèi)的基類(lèi)涯鲁,則可以使用PropertyChangeRegistry對(duì)象實(shí)現(xiàn)Observable接口,以有效地注冊(cè)和通知偵聽(tīng)器有序。

生成綁定類(lèi)

數(shù)據(jù)綁定庫(kù)生成用于訪問(wèn)布局的變量和視圖的綁定類(lèi)抹腿。此頁(yè)面顯示如何創(chuàng)建和自定義生成的綁定類(lèi)。

生成的綁定類(lèi)將布局變量與布局中的視圖鏈接起來(lái)旭寿。綁定類(lèi)的名稱(chēng)和包可以customized警绩。所有生成的綁定類(lèi)都繼承自ViewDataBinding類(lèi)。

為每個(gè)布局文件生成一個(gè)綁定類(lèi)盅称。默認(rèn)情況下肩祥,類(lèi)的名稱(chēng)基于布局文件的名稱(chēng),將其轉(zhuǎn)換為Pascal大小寫(xiě)并向其添加Binding后綴缩膝。上面的布局文件名是activity_main.xml混狠,因此相應(yīng)生成的類(lèi)是ActivityMainBinding。該類(lèi)保存布局屬性(例如疾层,user變量)到布局視圖的所有綁定将饺,并且知道如何為綁定表達(dá)式賦值。

創(chuàng)建綁定對(duì)象

在對(duì)布局進(jìn)行inflating之后痛黎,應(yīng)該很快創(chuàng)建綁定對(duì)象予弧,以確保在使用布局中的表達(dá)式綁定到視圖之前不會(huì)修改視圖層次結(jié)構(gòu)。將對(duì)象綁定到布局的最常用方法是使用綁定類(lèi)上的靜態(tài)方法湖饱。您可以通過(guò)使用inflate()綁定類(lèi)的方法來(lái)擴(kuò)展視圖層次結(jié)構(gòu)并將對(duì)象綁定到該層次結(jié)構(gòu)桌肴,如以下示例所示:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater());
}

除了LayoutInflater對(duì)象之外,inflate()方法還有另一個(gè)版本琉历,它接受ViewGroup對(duì)象坠七,如下面的示例所示:

MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false);

如果使用不同的機(jī)制對(duì)布局進(jìn)行inflate水醋,則可以將其單獨(dú)綁定,如下所示:

MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);

有時(shí)無(wú)法預(yù)先知道綁定類(lèi)型彪置。在這種情況下拄踪,可以使用DataBindingUtil類(lèi)創(chuàng)建綁定,如下面的代碼片段所示:

View viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent);
ViewDataBinding binding = DataBindingUtil.bind(viewRoot);

如果您在 Fragment, ListView, or RecyclerView adapter,中使用數(shù)據(jù)綁定拳魁,您可能更喜歡使用bindings類(lèi)或DataBindingUtil類(lèi)的inflate()方法惶桐,如下面的代碼示例所示:

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
// or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

帶ID的視圖

數(shù)據(jù)綁定庫(kù)在綁定類(lèi)中為布局中具有ID的每個(gè)視圖創(chuàng)建一個(gè)不可變字段。例如潘懊,數(shù)據(jù)綁定庫(kù)從以下布局中創(chuàng)建TextView類(lèi)型的firstName和lastName字段:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"
   android:id="@+id/firstName"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"
  android:id="@+id/lastName"/>
   </LinearLayout>
</layout>

該庫(kù)一次性從視圖層次結(jié)構(gòu)中提取包括id在內(nèi)的視圖姚糊。這種機(jī)制比為布局中的每個(gè)視圖調(diào)用findViewById()方法要快。

ID不是數(shù)據(jù)綁定的必要條件授舟,但是扔有些情況需要從代碼中訪問(wèn)視圖救恨。

變量

數(shù)據(jù)綁定庫(kù)為布局中聲明的每個(gè)變量生成訪問(wèn)器方法。例如释树,下面的布局在綁定類(lèi)中為user,image, andnote變量生成setter和getter方法:

<data>
   <import type="android.graphics.drawable.Drawable"/>
   <variable name="user" type="com.example.User"/>
   <variable name="image" type="Drawable"/>
   <variable name="note" type="String"/>
</data>

ViewStubs

? 與普通視圖不同肠槽,ViewStub對(duì)象一開(kāi)始是一個(gè)不可見(jiàn)的視圖。當(dāng)它們變得可見(jiàn)或被明確告知要inflate時(shí)奢啥,它們會(huì)通過(guò)inflate另一個(gè)布局來(lái)替換布局中的自己秸仙。

? 因?yàn)閂iewStub基本上從視圖層次結(jié)構(gòu)中消失,所以綁定對(duì)象中的視圖也必須消失桩盲,以便垃圾收集能夠會(huì)是它寂纪。因?yàn)橐晥D是最終的,所以一個(gè)ViewStubProxy對(duì)象在生成的綁定類(lèi)中代替了ViewStub赌结,當(dāng)ViewStub存在時(shí)捞蛋,您可以訪問(wèn)它,當(dāng)ViewStub inflated時(shí)姑曙,您還可以訪問(wèn)inflated視圖層次結(jié)構(gòu)襟交。

? 在inflating另一個(gè)布局時(shí)迈倍,必須為新布局建立綁定伤靠。因此,ViewStubProxy必須監(jiān)聽(tīng)ViewStub``OnInflateListener并在需要時(shí)建立綁定啼染。由于在給定的時(shí)間內(nèi)只能存在一個(gè)偵聽(tīng)器宴合,所以ViewStubProxy允許您設(shè)置一個(gè)OnInflateListener,它在建立綁定之后調(diào)用這個(gè)OnInflateListener迹鹅。

立即綁定

當(dāng)一個(gè)變量或可觀察對(duì)象發(fā)生變化時(shí)卦洽,數(shù)據(jù)綁定庫(kù)計(jì)劃在下一幀之前執(zhí)行綁定。然而斜棚,有時(shí)必須立即執(zhí)行綁定阀蒂。要強(qiáng)制執(zhí)行该窗,請(qǐng)使用executePendingBindings()方法。

高級(jí)綁定

動(dòng)態(tài)變量

有時(shí)蚤霞,特定的綁定類(lèi)是未知的酗失。例如,RecyclerView.Adapter針對(duì)任意布局的操作不知道特定的綁定類(lèi)昧绣。它仍然必須在調(diào)用onBindViewHolder()方法期間分配綁定值规肴。

在以下示例中,RecyclerView綁定的所有布局都具有 item變量夜畴。該BindingHolder對(duì)象有一個(gè)getBinding()返回ViewDataBinding基類(lèi)的方法 拖刃。

public void onBindViewHolder(BindingHolder holder, int position) {
    final T item = items.get(position);
    holder.getBinding().setVariable(BR.item, item);
    holder.getBinding().executePendingBindings();
}

注意:數(shù)據(jù)綁定庫(kù)在模塊包中生成一個(gè)名為BR的類(lèi),在上面的示例中贪绘,庫(kù)自動(dòng)生成BR.item變量兑牡。

后臺(tái)線程

您可以在后臺(tái)線程中更改除了集合以外的數(shù)據(jù)模型。數(shù)據(jù)綁定會(huì)在計(jì)算期間隔離每一個(gè)變量/字段以避免任何并發(fā)問(wèn)題

自定義綁定類(lèi)名稱(chēng)

默認(rèn)情況下兔簇,將根據(jù)布局文件的名稱(chēng)生成綁定類(lèi)发绢,以大寫(xiě)字母開(kāi)頭,刪除下劃線(_)垄琐,并大寫(xiě)后面一個(gè)字母边酒,且添加單詞Binding作為后綴。該類(lèi)放在 databinding模塊包下的包中狸窘。例如墩朦,布局文件 contact_item.xml生成ContactItemBinding類(lèi)。如果模塊包是com.example.my.app翻擒,則綁定類(lèi)放在 com.example.my.app.databinding包中氓涣。

通過(guò)調(diào)整data元素中的class屬性,可以重命名綁定類(lèi)或?qū)⒔壎?lèi)放在不同的包中 陋气。例如劳吠,下面的布局在當(dāng)前模塊的databinding包中生成ContactItem綁定類(lèi):

<data class="ContactItem">
    …
</data>

您可以通過(guò)在類(lèi)名前加一個(gè)句點(diǎn)在不同的包生成綁定類(lèi)。以下示例在模塊包中生成綁定類(lèi):

<data class=".ContactItem">
    …
</data>

你可以使用完整包名在你想要的包中生成綁定類(lèi)巩趁。以下示例ContactItemcom.example包中創(chuàng)建綁定類(lèi) :

<data class="com.example.ContactItem">
    …
</data>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末痒玩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子议慰,更是在濱河造成了極大的恐慌蠢古,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件别凹,死亡現(xiàn)場(chǎng)離奇詭異草讶,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)炉菲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)堕战,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)坤溃,“玉大人,你說(shuō)我怎么就攤上這事嘱丢〗奖ⅲ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵屿讽,是天一觀的道長(zhǎng)昭灵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)伐谈,這世上最難降的妖魔是什么烂完? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮诵棵,結(jié)果婚禮上抠蚣,老公的妹妹穿的比我還像新娘。我一直安慰自己履澳,他們只是感情好嘶窄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著距贷,像睡著了一般柄冲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上忠蝗,一...
    開(kāi)封第一講書(shū)人閱讀 51,554評(píng)論 1 305
  • 那天现横,我揣著相機(jī)與錄音,去河邊找鬼阁最。 笑死戒祠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的速种。 我是一名探鬼主播姜盈,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼配阵!你這毒婦竟也來(lái)了馏颂?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤闸餐,失蹤者是張志新(化名)和其女友劉穎饱亮,沒(méi)想到半個(gè)月后矾芙,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體舍沙,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年剔宪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拂铡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片壹无。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖感帅,靈堂內(nèi)的尸體忽然破棺而出斗锭,到底是詐尸還是另有隱情,我是刑警寧澤失球,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布岖是,位于F島的核電站,受9級(jí)特大地震影響实苞,放射性物質(zhì)發(fā)生泄漏豺撑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一黔牵、第九天 我趴在偏房一處隱蔽的房頂上張望聪轿。 院中可真熱鬧,春花似錦猾浦、人聲如沸陆错。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)音瓷。三九已至,卻和暖如春夹抗,著一層夾襖步出監(jiān)牢的瞬間外莲,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工兔朦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留偷线,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓沽甥,卻偏偏與公主長(zhǎng)得像声邦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子摆舟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 今天是春運(yùn)的倒數(shù)第五天亥曹,我到車(chē)站查危,原以為春運(yùn)接近尾聲車(chē)站的人流應(yīng)該不大恨诱。到了之后才發(fā)現(xiàn)自己錯(cuò)了媳瞪,九點(diǎn)前還好,九...
    盈盈清泉閱讀 448評(píng)論 9 1
  • 圖/文:葉薄荷 我是特別害怕冬天的照宝。佛家有句話叫“饑來(lái)吃飯困來(lái)眠”蛇受,說(shuō)的是餓了便吃飯,倦了便安眠厕鹃,該做什么就做什么...
    葉薄荷閱讀 479評(píng)論 13 6
  • 天頂?shù)纳钏{(lán)轉(zhuǎn)為漆黑兢仰,星光若隱若現(xiàn)乍丈,玩著捉迷藏。小馬坐起來(lái)把将,游樂(lè)場(chǎng)的燈光很耀眼轻专,因?yàn)樘h(yuǎn)而蒙上一層水汽一般的朦朧。突...
    Chros閱讀 766評(píng)論 9 15
  • 服務(wù)端要求: (dhcp已經(jīng)配好) 運(yùn)行dhcp服務(wù)察蹲,用來(lái)分配地址请垛,定位引導(dǎo)程序 運(yùn)行tftp服務(wù),提供引導(dǎo)程序下...
    孫睿888閱讀 704評(píng)論 1 0
  • 近日,幾張圖片在微博里熱傳绞铃,原來(lái)是上海某公司因?yàn)檗k公環(huán)境太漂亮而在網(wǎng)絡(luò)上走紅镜雨。網(wǎng)友看到這條消息后,紛紛表示想去上班...
    tzKN閱讀 226評(píng)論 0 0