DataBinding的简单使用

Table of Contents

参考文章:https://www.jianshu.com/p/ba4982be30f8

环境配置

在 gradle 里添加对 dataBinding 的支持:

    android{
        ...
        dataBinding{
            enable = true
        }
    }

安装插件:Databinding Support 对 layout 文件支持,Data Binding Formatter 对 class 文件支持

使用

编写布局文件,使用变量:

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">

        <data>
            <variable
                name="viewModel"
                type="com.example.Article"/>
        </data>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="@dimen/activity_horizontal_margin">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{viewModel.title}"
                android:textSize="@dimen/base_font_size_large_18"
                android:textStyle="bold"/>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:layout_marginTop="10dp">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@{viewModel.view+`次浏览`}"/>
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@{viewModel.like+`个喜欢`}"
                    android:layout_marginLeft="10dp"/>
                <EditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:value="@={viewModel.reader}"/>

            </LinearLayout>
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                bind:bindSrcToImage="@{viewModel.image}"
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="已阅"
                android:onClick="@{viewModel::onClickRead}"/>

        </LinearLayout>
    </layout>

在 layout 文件中使用 Article 对象,要想把 Article 对象的相关字段绑定在 UI 上,还需要申明这些字段是“可观察的”,可以这样实现:

  1. 继承 BaseObservable,然后用@Bindable 注解需要观察的属性
  2. 使用 ObseravbleField 类型包裹属性

Android studio 会根据 layout 文件自动生成一个默认的 Binding 类,类名是根据 layout 文件名生成的,并有"Binding"后缀结束。例如:activity_article.xml 生成的 Binding 类为 ActivityArticleBinding,可用如下方式使用 Binding 类:

    ActivityArticleBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_article);
    Article article = new Article();
    binding.setViewModel(article);

或者:

    ActivityArticleBinding binding = ActivityArticleBinding.inflate(getLayoutInflater());

在 RecyclerView 的 adapter 中的 item 里使用 DataBinding:

    ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
    //or
    ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

在 layout 中绑定的 onClickRead 方法只需要在 Article 中实现一个 public 的 onClickRead 方法即可

在 layout 中申明的 bindSrcToImage 属性需要加@BindingAdapter 注解实现逻辑,如:

    @BindingAdapter("bind:bindSrcToImage")
    public static void setSrcToImage(ImageView imageView,String src){
        Glide.with(mContext).load(src).into(imageView);
    }

使用同样方法可以覆盖控件的原 set 方法实现,且可以同时处理多个属性,如:

    @BindingAdapter({"android:onClick", "android:clickable"})
    public static void setOnClick(View view, View.OnClickListener clickListener,
                                   boolean clickable) {
         view.setOnClickListener(clickListener);
         view.setClickable(clickable);
     }

使用 import 标签导入类,然后可以使用类的静态资源:

    <data>
        <import type="android.view.View"/>
    </data>

    <TextView
       android:text="@{article.content}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:visibility="@{article.isFold ? View.VISIBLE : View.GONE}"/>

有时候我们可能不知道 Binding 类的名称,比如 RecyclerView.Adapter 中 item 布局可能有很多,并不会对应特定的 Binding 类,但是仍然需要通过 onBindViewHolder(VH, int)去绑定数据,下面的例子是,所有的子布局都有一个"item"变量(所有申明的变量都在 BR 文件里面),通过 ViewDataBinding 基类去完成绑定:

    public void onBindViewHolder(BindingHolder holder, int position) {
       final T item = mItems.get(position);
       holder.getBinding().setVariable(BR.item, item);
       holder.getBinding().executePendingBindings();
    }

有时候我们需要自定义属性变化的业务逻辑,我们可以给 Observable 变量设置变化监听:

    ObservableInt flag = new ObservableInt();
    flag.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
                @Override
                public void onPropertyChanged(Observable sender, int propertyId) {
                    if(sender.get() == 0){
                        finish();
                    }
                }
            });

有时候我们想要在类里面申明的数据类型和 layout 里面使用的数据类型不一样,那我们可以使用@BindingConversion 注解实现,比如将整型颜色值转化为 Drawable:

    @BindingConversion
    public static ColorDrawable convertColorToDrawable(int color) {
       return new ColorDrawable(color);
    }