上一节简单的使用Data Binding 库与界面绑定数据与事件处理,当数据更新后,使用mBinding.setCompany(mCompany);方法可以把界面上的数据全部更新一次。
如果只想在类的某个成员变量更新时相应也只更新相对应的界面,而不是layout里绑定的全部数据时,Data Binding 库也提供了相应的类,还提供了一个监听属性字段变化的回调。
java的基本数据类型都有一个对的包装类。如int对应Integer,long对应于Long,boolean对应Boolean。
类似的Data Binding 库对于成员变量也有相对应的包装类。如下图:
1.当类的成员变量值变化时,通知相应的回调接口
1.1新建对应的java类继承BaseObservable,并用Observablexxx包装相应的成员变量,在相应的get方法上使用@Bindable,@BindingAdapter注解,如下所示
public class BRCompany extends BRBaseObservable{ public ObservableFieldnameField = new ObservableField<>(); public ObservableField iconField = new ObservableField<>(); public ObservableField 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相对较少使用这一个特性。)
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类也有一个类似的方法和回调接口,
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
<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 ObservableFieldnameField = new ObservableField<>(); public ObservableField iconField = new ObservableField<>(); public ObservableField 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
但对应的get方法不是 getNameField 而是 @Bindable public String getBRName();
所以建议在使用Observablexxxx包装类时,成员变量名字叫name时,不要直接发使作@Bindable注解getName方法,否则可能会造成误解。
还有比较坑的就是,在因为在layout里使用不当造成编译失败的时候,提示不太友好,会很难找出哪里错了。
完整代码请查看
https://git.oschina.net/null_979_4294/MVP-DataBinding1