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

相关文章
相关标签/搜索