DataBinding - SMAXLYB/JetpackPractice GitHub Wiki

DataBinding

页面承担了查找UI控件的责任,DataBinding的出现承担了原本属于页面的工作,使得页面和布局的耦合度进一步降低。

  • 如何使用:
    1. 添加依赖
    2. 获得控件:在布局文件外层加入标签,build之后会生成xxxBinding类,在页面中无需findViewById(),直接binding.setContentView()后,就可以通过binding直接获得控件
    3. 传递数据:布局文件中标签新增标签,在标签中新增,在页面中即可传入数据,在布局中使用表达式@{}即可使用数据,当数据改变时,会自动修改UI
    4. 引入布局:在标签中,使用app自定义属性,即可将数据传入布局,引入的布局也要新增标签
    5. 自定义BindingAdapter:新增方法,方法使用@BindingAdapter(xx)注解,方法第一个参数必须为当前View,其他参数可以自己设置,在布局中即可使用app引入自定义属性
    6. 双向绑定:使用@={}引用可观察字段
      1. 第一种方式:自定义类继承自BaseObservable,字段需要添加getter和setter,setter需要调用notifyPropertyChanged(),getter需要@Bindable注解
      2. 第二种方式:使用observableFiled包装字段
  • 相关注解
    1. @BindingMethod(type:哪个view,attribute:哪个属性,method: 哪个方法),如果xml中使用了android:hint,默认会绑定setHint方法,如果没有找到就会报错,所以要另外编写一个类,然后添加注解去调指明绑定哪个方法,一般和@BindingMethods共同配合使用,具体例子可以看ImageViewBindingAdapter
    2. @InverseBindingMethod
@InverseBindingMethods({
        @InverseBindingMethod(type = RatingBar.class, attribute = "android:rating"),
})
public class RatingBarBindingAdapter {
    // 这里一定要重新定义一个新方法,即使原来已经有setRating方法,如果不定义的话,原来的set方法没做跳出循环的判断
    @BindingAdapter("android:rating")
    public static void setRating(RatingBar view, float rating) {
        // 如果是单项绑定的话,直接set影响到了view,但是view不会再去更新源数据,
        // 如果是双向绑定,直接set会影响view,view又会更新源数据,然后源数据变化又调用set,然后往复循环,所以这里必须做判断
        if (view.getRating() != rating) {
            view.setRating(rating);
        }
    }

    @BindingAdapter(value = {"android:onRatingChanged", "android:ratingAttrChanged"},
            requireAll = false)
    public static void setListeners(RatingBar view, final OnRatingBarChangeListener listener,
            final InverseBindingListener ratingChange) {
        // 设置监听,当view的状态发生改变时,更新源数据
        if (ratingChange == null) {
            view.setOnRatingBarChangeListener(listener);
        } else {
            view.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {
                @Override
                public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
                    if (listener != null) {
                        listener.onRatingChanged(ratingBar, rating, fromUser);
                    }
                    ratingChange.onChange();
                }
            });
        }
    }
}
  1. @BindingAdapter,当xml中没有你要的属性android:xxxx, 那么可以自己定义一个方法,当绑定的数据改变的时候会调这个方法,具体例子看TextViewBindingAdapter
  2. @InverseBindingAdapter(attribute,event),配合@BindingAdapter进行监听绑定,完成双向绑定,主要作用是获取view的数据,转换成和源数据的类型,并通知dataBinding数据发生了改变
  3. @BindingConversion,单向绑定,如果一个属性需要drawable,但是你的类型时int,那么进行绑定的时候需要转换数据,另写一个方法,入参和返回值要对应,然后添加注解,具体例子看Converters
  4. @InverseMethod,上面是针对单向的,如果是双向,那么xml属性改变的时候会给你的类型赋值,也就是drawable到int,同样也需要转换,具体例子:
@InverseMethod("convertIntToString")
public static int convertStringToInt(String value) {
    try {
        return Integer.parseInt(value);
    } catch (NumberFormatException e) {
        return -1;
    }
}
public static String convertIntToString(int value) {
    return String.valueOf(value);
}
⚠️ **GitHub.com Fallback** ⚠️