Jetpack學習3--使用可觀察的對象&生成綁定類

[TOC]

Jetpack學習3--使用可觀察的對象&生成綁定類

使用可觀察的對象

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

任何普通的舊對象都可以用于數(shù)據綁定,但是修改對象不會自動導致UI更新。數(shù)據綁定可用于使數(shù)據對象能夠在數(shù)據發(fā)生更改時通知其他對象,即偵聽器。有三種不同類型的可觀察類:objects, fields, and collections.

當其中一個可觀察數(shù)據對象綁定到UI并且數(shù)據對象的屬性發(fā)生更改時,UI將自動更新。

可觀察的字段

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

可觀察字段是具有單個字段的自包含可觀察對象。原始版本在訪問操作期間避免裝箱和解箱。要使用這種機制,請在Java編程語言中創(chuàng)建一個public final屬性,或者在Kotlin中創(chuàng)建一個只讀屬性,如下面的示例所示:

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

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

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

注意:Android Studio 3.1及更高版本允許您使用LiveData對象替換可觀察字段,這為您的應用提供了額外的好處。有關更多信息,請參閱使用LiveData通知UI有關數(shù)據更改的信息

可觀察的集合

一些應用程序使用動態(tài)結構來保存數(shù)據。可觀察集合允許使用密鑰訪問這些結構。如果鍵是引用類型,比如字符串,ObservableArrayMap類非常有用,如下面的例子所示:

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

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

<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"/>

當key是int時可以使用ObservableArrayList,如下:

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

在布局中,可以通過索引訪問列表,如以下示例所示:

<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"/>

可觀察對象

實現(xiàn)Observable接口的類可以注冊監(jiān)聽器,當可觀察對象屬性改變時可以通知它。

Observable接口具有添加和刪除偵聽器的機制,但是您必須決定何時發(fā)送通知。為了簡化開發(fā),數(shù)據綁定庫提供了BaseObservable類,該類實現(xiàn)偵聽器注冊機制。實現(xiàn)BaseObservable的數(shù)據類負責在屬性發(fā)生變化時發(fā)出通知。這是通過為getter分配一個Bindable注解,并在setter中調用notifyPropertyChanged()方法來實現(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ù)據綁定在模塊包中生成一個名為BR的類,該類包含用于數(shù)據綁定的資源的id。Bindable注解在編譯期間在BR類文件中生成一個條目。如果不能更改數(shù)據類的基類,則可以使用PropertyChangeRegistry對象實現(xiàn)Observable接口,以有效地注冊和通知偵聽器。

生成綁定類

數(shù)據綁定庫生成用于訪問布局的變量和視圖的綁定類。此頁面顯示如何創(chuàng)建和自定義生成的綁定類。

生成的綁定類將布局變量與布局中的視圖鏈接起來。綁定類的名稱和包可以customized。所有生成的綁定類都繼承自ViewDataBinding類。

為每個布局文件生成一個綁定類。默認情況下,類的名稱基于布局文件的名稱,將其轉換為Pascal大小寫并向其添加Binding后綴。上面的布局文件名是activity_main.xml,因此相應生成的類是ActivityMainBinding。該類保存布局屬性(例如,user變量)到布局視圖的所有綁定,并且知道如何為綁定表達式賦值。

創(chuàng)建綁定對象

在對布局進行inflating之后,應該很快創(chuàng)建綁定對象,以確保在使用布局中的表達式綁定到視圖之前不會修改視圖層次結構。將對象綁定到布局的最常用方法是使用綁定類上的靜態(tài)方法。您可以通過使用inflate()綁定類的方法來擴展視圖層次結構并將對象綁定到該層次結構,如以下示例所示:

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

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

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

如果使用不同的機制對布局進行inflate,則可以將其單獨綁定,如下所示:

MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);

有時無法預先知道綁定類型。在這種情況下,可以使用DataBindingUtil類創(chuàng)建綁定,如下面的代碼片段所示:

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

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

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

帶ID的視圖

數(shù)據綁定庫在綁定類中為布局中具有ID的每個視圖創(chuàng)建一個不可變字段。例如,數(shù)據綁定庫從以下布局中創(chuàng)建TextView類型的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>

該庫一次性從視圖層次結構中提取包括id在內的視圖。這種機制比為布局中的每個視圖調用findViewById()方法要快。

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

變量

數(shù)據綁定庫為布局中聲明的每個變量生成訪問器方法。例如,下面的布局在綁定類中為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對象一開始是一個不可見的視圖。當它們變得可見或被明確告知要inflate時,它們會通過inflate另一個布局來替換布局中的自己。

? 因為ViewStub基本上從視圖層次結構中消失,所以綁定對象中的視圖也必須消失,以便垃圾收集能夠會是它。因為視圖是最終的,所以一個ViewStubProxy對象在生成的綁定類中代替了ViewStub,當ViewStub存在時,您可以訪問它,當ViewStub inflated時,您還可以訪問inflated視圖層次結構。

? 在inflating另一個布局時,必須為新布局建立綁定。因此,ViewStubProxy必須監(jiān)聽ViewStub``OnInflateListener并在需要時建立綁定。由于在給定的時間內只能存在一個偵聽器,所以ViewStubProxy允許您設置一個OnInflateListener,它在建立綁定之后調用這個OnInflateListener

立即綁定

當一個變量或可觀察對象發(fā)生變化時,數(shù)據綁定庫計劃在下一幀之前執(zhí)行綁定。然而,有時必須立即執(zhí)行綁定。要強制執(zhí)行,請使用executePendingBindings()方法。

高級綁定

動態(tài)變量

有時,特定的綁定類是未知的。例如,RecyclerView.Adapter針對任意布局的操作不知道特定的綁定類。它仍然必須在調用onBindViewHolder()方法期間分配綁定值。

在以下示例中,RecyclerView綁定的所有布局都具有 item變量。該BindingHolder對象有一個getBinding()返回ViewDataBinding基類的方法 。

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

注意:數(shù)據綁定庫在模塊包中生成一個名為BR的類,在上面的示例中,庫自動生成BR.item變量。

后臺線程

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

自定義綁定類名稱

默認情況下,將根據布局文件的名稱生成綁定類,以大寫字母開頭,刪除下劃線(_),并大寫后面一個字母,且添加單詞Binding作為后綴。該類放在 databinding模塊包下的包中。例如,布局文件 contact_item.xml生成ContactItemBinding類。如果模塊包是com.example.my.app,則綁定類放在 com.example.my.app.databinding包中。

通過調整data元素中的class屬性,可以重命名綁定類或將綁定類放在不同的包中 。例如,下面的布局在當前模塊的databinding包中生成ContactItem綁定類:

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

您可以通過在類名前加一個句點在不同的包生成綁定類。以下示例在模塊包中生成綁定類:

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

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

<data class="com.example.ContactItem">
    …
</data>
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • 今天是春運的倒數(shù)第五天,我到車站查危,原以為春運接近尾聲車站的人流應該不大。到了之后才發(fā)現(xiàn)自己錯了,九點前還好,九...
    盈盈清泉閱讀 453評論 9 1
  • 圖/文:葉薄荷 我是特別害怕冬天的。佛家有句話叫“饑來吃飯困來眠”,說的是餓了便吃飯,倦了便安眠,該做什么就做什么...
    葉薄荷閱讀 490評論 13 6
  • 天頂?shù)纳钏{轉為漆黑,星光若隱若現(xiàn),玩著捉迷藏。小馬坐起來,游樂場的燈光很耀眼,因為太遠而蒙上一層水汽一般的朦朧。突...
    Chros閱讀 773評論 9 15
  • 服務端要求: (dhcp已經配好) 運行dhcp服務,用來分配地址,定位引導程序 運行tftp服務,提供引導程序下...
    孫睿888閱讀 709評論 1 0
  • 近日,幾張圖片在微博里熱傳,原來是上海某公司因為辦公環(huán)境太漂亮而在網絡上走紅。網友看到這條消息后,紛紛表示想去上班...
    tzKN閱讀 231評論 0 0