Android中的MVP笔记之三: Data Binding 库的使用之对象数据变化与界面同步更新

上一节简单的使用Data Binding 库与界面绑定数据与事件处理,当数据更新后,使用mBinding.setCompany(mCompany);方法可以把界面上的数据全部更新一次。

如果只想在类的某个成员变量更新时相应也只更新相对应的界面,而不是layout里绑定的全部数据时,Data Binding 库也提供了相应的类,还提供了一个监听属性字段变化的回调。

 java的基本数据类型都有一个对的包装类。如int对应Integer,long对应于Long,boolean对应Boolean。

类似的Data Binding 库对于成员变量也有相对应的包装类。如下图:

Android中的MVP笔记之三: Data Binding 库的使用之对象数据变化与界面同步更新_第1张图片

 

1.当类的成员变量值变化时,通知相应的回调接口

1.1新建对应的java类继承BaseObservable,并用Observablexxx包装相应的成员变量,在相应的get方法上使用@Bindable,@BindingAdapter注解,如下所示

public class BRCompany extends BRBaseObservable{
    public ObservableField nameField = 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 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);方法时就可以同步更新界面。

 

注意事项

Android中的MVP笔记之三: Data Binding 库的使用之对象数据变化与界面同步更新_第2张图片

在生成的临时文件里,会有上面的一个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 nameField = 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 nameField = new ObservableField<>();

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

所以建议在使用Observablexxxx包装类时,成员变量名字叫name时,不要直接发使作@Bindable注解getName方法,否则可能会造成误解。

还有比较坑的就是,在因为在layout里使用不当造成编译失败的时候,提示不太友好,会很难找出哪里错了。

 

完整代码请查看

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

转载于:https://my.oschina.net/u/3038281/blog/861054

你可能感兴趣的:(Android中的MVP笔记之三: Data Binding 库的使用之对象数据变化与界面同步更新)