Bindable
使用场景
data binding的意义主要数据的变动可以自动触发UI界面的刷新。但是如果我们使用的是传统的java bean对象的时候,是没有办法实现“数据变更触发ui界面”的目的的。而 Bindable 注解就是帮助我们完成这个任务的。
如果我们要实现“数据变更触发ui界面”的话,途径主要有两个:
1. 继承 BaseObservable ,使用 Bindable 注解field的getter并且在调用setter的使用使用 OnPropertyChangedCallback#onPropertyChanged
2. 使用data-binding library当中提供的诸如 ObservableField<> , ObservableInt作为属性值
代码定义
/**
* The Bindable annotation should be applied to any getter accessor method of an
* {@link Observable} class. Bindable will generate a field in the BR class to identify
* the field that has changed.
*
* @see OnPropertyChangedCallback#onPropertyChanged(Observable, int)
*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) // this is necessary for java analyzer to work
public @interface Bindable {
}
使用解析
根据上面代码中的注释我们可以知道,Bindable 是对继承了 Observable 的类当中的 getter 方法进行注解。并且当我们使用了这个注解的时候,databinding library 会在 BR 这个类当中生成一个属性,用以标识发生了变化的属性field
使用示例
public class PrivateUser extends BaseObservable{
private String fistName;
private String lastName;
public PrivateUser(String fistName, String lastName) {
this.age = age;
this.fistName = fistName;
this.lastName = lastName;
}
@Bindable
public String getFistName() {
return fistName;
}
public void setFistName(String fistName) {
this.fistName = fistName;
notifyPropertyChanged(BR.fistName);
}
@Bindable
public String getLastName() {
return lastName;
}
public void setLasetName(String lasetName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
}
使用心得
- 根据 Bindable 的定义可以发现,Bindable 是支持对属性进行注解的,所以当我们的属性是public的(不需要通过getter进行访问)的时候,是可以在属性上面使用该注解的。但是改变属性的值的时候是一定要调用 onPropertyChanged() 这个方法的,否则无法实现通知刷新UI的功能;
- 上面频繁出现的 BR 这个类是在编译的时候生成的,使用的时候可能会发现ide没办法找到我们的属性,比如BR.lastName ,只要rebuild一下就可以了。
BindingAdapter
使用场景
当我们使用data binding的时候,data-binding library会尽可能的找到给view对应的属性(Attribute)进行赋值的方法,通常这个方法的名称就是set${Attribute}。这时候属性前面的命名空间会被忽略,而只关注属性的名称。比如我们数据绑定了TextView的 android:text 属性,那么data-binding library会去寻找 setText(String) 这样的一个方法。
BindingAdapter 注解的方法能够控制给view赋值的操作过程,也就是说可以实现自定义setter的实现。对于那些不具备对应setter方法的属性(比如我们要绑定一个 android:paddingLeft 的属性的时候,我们却只有 setPadding(left, top, right, bottom) 这样的一个setter方法),那么我们可以通过BindingAdapter 注解来实现一个自定义的setter;比如我们希望给ImageView设置了一个字符串URL的值的时候,ImageView能够根据这个URL进行自主的联网下载图片的操作。
此外我们还可以覆盖原有的setter方法的逻辑,比如我们使用 BindingAdapter 的时候参数传入的是 android:text ,那么我们方法的实现逻辑就会复写原来的setText(String)的方法逻辑了
代码定义
@Target(ElementType.METHOD)
public @interface BindingAdapter {
/**
* @return The attributes associated with this binding adapter.
*/
String[] value();
/**
* Whether every attribute must be assigned a binding expression or if some
* can be absent. When this is false, the BindingAdapter will be called
* when at least one associated attribute has a binding expression. The attributes
* for which there was no binding expression (even a normal XML value) will
* cause the associated parameter receive the Java default value. Care must be
* taken to ensure that a default value is not confused with a valid XML value.
*