上一節簡單的使用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裏使用不當形成編譯失敗的時候,提示不太友好,會很難找出哪裏錯了。
完整代碼請查看