1. 程式人生 > >android Data Binding 資料變化監聽

android Data Binding 資料變化監聽

本文參考databinding官方文件整理。官方文件連結地址https://developer.Android.com/topic/libraries/data-binding/index.html#data_binding_layout_files

Data Objects


Any plain old Java object (POJO) may be used for data binding, but modifying a POJO will not cause the UI to update. The real power of data binding can be used by giving your data objects the ability to notify when data changes. There are three different data change notification mechanisms,

Observable objectsobservable fields, and observable collections.

When one of these observable data object is bound to the UI and a property of the data object changes, the UI will be updated automatically.

以上文字引用自官方文件,大致意思就是傳統的java物件都可以用於data binding,但是修改一個被繫結的物件並不能保證它能成功通知UI重新整理,所有官方給出來三種方式來解決這個問題,確保一個被繫結的物件發生變化時能保證對應的UI做出相應變化。三種方式分別為Observable objects, observable fields, and observable collections。


第一種方式Observable objects

讓物件繼承BaseObservable,在需要刷UI的欄位被改變時通知監聽著變化,舉例如下:

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);    } }
firstName和lastName被賦值時候呼叫了notifyPropertyChanged通知監聽者做出對應變化,個人認為這種方式的好處是可以控制那些欄位的更新需要通知UI變化;缺點時java的單一繼承使得此類不能有其它父類。

第二種方式observable fields

使用ObservableField來定義那些需要通知UI變化的欄位,欄位值改變後觀察者能及時收到資料改變的通知,舉例如下:


private static class User {
   public final ObservableField<String> firstName =
       new ObservableField<>();
   public final ObservableField<String> lastName =
       new ObservableField<>();
   public final ObservableInt age = new ObservableInt();
}
使用舉例如下:
user.firstName.set("Google");
int age = user.age.get()

這種方式保留了第一種方式的靈活性,同時解決了第一種方式中存在的單一繼承問題。


第三種方式 observable collections

使用監聽者集合。將欄位新增到一個集合中,使用時候根據key獲取到對應值,集合中欄位變化時候也能通知到監聽者。舉例如下:

定義一個ObservableArrayMap集合

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

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


定義一個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&lt;Object&gt;"/>
</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"/>

這種方式存在資料相容問題,如果定義資料型別為object,存在大量的資料轉換,效率不高。


最後,雖然谷歌給出多種方式來實現資料通知,但是實際使用過程中android:text="@{user.lastName}"暫未見到資料改變,UI不更新的問題,這也許跟本人的使用深度有關係。同樣,android:text="@={user.lastName}"實現雙向繫結時候也未發現UI資料變化後,user中對應欄位未更新的情況。