Android中的MVP筆記之三: Data Binding 庫的使用之對象數據變化與界面同步更新

上一節簡單的使用Data Binding 庫與界面綁定數據與事件處理,當數據更新後,使用mBinding.setCompany(mCompany);方法能夠把界面上的數據所有更新一次。java

若是隻想在類的某個成員變量更新時相應也只更新相對應的界面,而不是layout裏綁定的所有數據時,Data Binding 庫也提供了相應的類,還提供了一個監聽屬性字段變化的回調。android

 java的基本數據類型都有一個對的包裝類。如int對應Integer,long對應於Long,boolean對應Boolean。git

相似的Data Binding 庫對於成員變量也有相對應的包裝類。以下圖:ide

 

1.當類的成員變量值變化時,通知相應的回調接口this

1.1新建對應的java類繼承BaseObservable,並用Observablexxx包裝相應的成員變量,在相應的get方法上使用@Bindable,@BindingAdapter註解,以下所示url

public class BRCompany extends BRBaseObservable{
    public ObservableField<String> nameField = new ObservableField<>();
    public ObservableField<String> iconField = new ObservableField<>();
    public ObservableField<String> infoField = new ObservableField<>();
    public ObservableLong createTimeField = new ObservableLong();

    public BRCompany(String name, String icon, String info, long createTime) {
        this.nameField.set(name);
        this.iconField.set(icon);
        this.infoField.set(info);
        this.createTimeField.set(createTime);
    }

    @BindingAdapter({"bind:imageUrl", "bind:error"})
    public static void setIcon(ImageView view, String url, Drawable error) {
        Glide.with(view.getContext()).load(url).error(error).into(view);
    }

    @Bindable
    public String getBRName() {
        return nameField.get();
    }

    public void setName(String name) {
        this.nameField.set(name);
    }
    ...省略n行代碼,完整請查看完整工程。
}

作安卓開發的都知道有一個叫EditText的輸入控件,在輸入內容變化時,有相應的接口回調相應的輸入內容(這一個特性實際上是EditText的父類TextView的方法,但常常用在EditText輸入變化時使用,TextView相對較少使用這一個特性。)spa

public void addTextChangedListener(TextWatcher watcher)
public void removeTextChangedListener(TextWatcher watcher)

public interface TextWatcher extends NoCopySpan {
    public void beforeTextChanged(CharSequence s, int start,int count, int after);
    public void onTextChanged(CharSequence s, int start, int before, int count);
    public void afterTextChanged(Editable s);
}

相似的Data Binding 庫對成員變量的包裝Observablexxx類也有一個相似的方法和回調接口,.net

public void addOnPropertyChangedCallback(OnPropertyChangedCallback callback)
public void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) 

public abstract static class OnPropertyChangedCallback {
    public OnPropertyChangedCallback() {
    }

    public abstract void onPropertyChanged(Observable var1, int var2);
}

使用方法也相似,只是一個是在輸入內容發生變化時回調,一個是在調用set方法時回調。繼承

mCompany.nameField.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
    @Override
    public void onPropertyChanged(Observable observable, int i) {
        Log.d("onPropertyChanged","name:"+mCompany.nameField);
    }
});

 

2.在成員變量值變化時讓layout裏綁定這個成員變量的控件也同時變化。接口

如上面所示,新建相應的java類後,在layout裏作相應的引用,注意是以成員變量名稱方式引用,即定方義了public ObservableField<String> nameField = new ObservableField<>();是使用brCompany.nameField ,而不是使用對應的get方法。

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
 android:text='@{"name:"+brCompany.nameField}'
        android:textSize="16sp" />

    <TextView
        android:id="@+id/tv_create_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
 android:text="@{DateUtil.getTime(brCompany.createTimeField)}"
        android:textSize="16sp" />
</LinearLayout>

而後在調用mCompany.setName(s);方法時就能夠同步更新界面。

 

注意事項

在生成的臨時文件裏,會有上面的一個BR文件,和R文件相似,生成的都是一個相似id的屬性。

public class Company extends BaseObservable {
    public String name;
    private String icon;
    private String info;
    private long createTime;
    ...省略n行代碼。

    @Bindable
    public String getName() {
        return name;
    }
}

上面的類生成了圖中對應的11~15行數據。

 

public class BRCompany extends BRBaseObservable{
    public ObservableField<String> nameField = new ObservableField<>();
    public ObservableField<String> iconField = new ObservableField<>();
    public ObservableField<String> infoField = new ObservableField<>();
    public ObservableLong createTimeField = new ObservableLong();
     ...省略n行代碼。
    @Bindable
    public String getBRName() {
        return nameField.get();
    }
}

上面的類生成了圖中對應的6~10行數據。

 

以Company類爲例定義了一個public String name;屬性,也註解一個方法

@Bindable    public String getName()

因此在layout裏能夠有兩種引用方法

以方法形式引用

android:text='@{"name:"+company.getName()}'

以BR文件裏生成的name屬性形式引用。

android:text='@{"name:"+company.name}'

 

對比使用了上面兩個類的成員變量名稱,可知其實BR文件裏的屬性值是根據get方法名稱生成的,不是根據屬性名稱生成的,全部會有一個坑就是,當使用了 Observablexxx包裝成員變量n,並且有一個getN的方法裏,但在layout使用了BR文件裏生成的對應屬性形式引用時,Observablexxx包裝過的成員變量值發生變化時,界面不會發生變化,因此示例中定義時

public ObservableField<String> nameField = new ObservableField<>();

但對應的get方法不是 getNameField  而是 @Bindable public String getBRName();

因此建議在使用Observablexxxx包裝類時,成員變量名字叫name時,不要直接發使做@Bindable註解getName方法,不然可能會形成誤解。

還有比較坑的就是,在由於在layout裏使用不當形成編譯失敗的時候,提示不太友好,會很難找出哪裏錯了。

 

完整代碼請查看

https://git.oschina.net/null_979_4294/MVP-DataBinding1

相關文章
相關標籤/搜索