46、DataBinding入门:启用DataBinding、绑定数据、双向绑定、BindingAdapter

DataBinding,说白了就是让布局文件也能干活。以前我们写Android,布局是布局,逻辑是逻辑,中间靠findViewById牵线搭桥。我个人习惯是,项目一启动就把DataBinding配上,省得后面再改麻烦。

这一章,我带你把DataBinding的四个核心点过一遍:怎么启用、怎么绑定数据、怎么玩双向绑定、以及自定义BindingAdapter。嗯,都是实战里天天用的东西。

一、启用DataBinding

先别急着写代码,得先把环境搭好。在模块的build.gradle里加上这么一段:

android {
    ...
    buildFeatures {
        dataBinding = true
    }
}

就这么简单。同步一下,DataBinding就启用了。我在项目中遇到过有人忘了加这个,结果编译报错半天找不到原因——嗯,这种坑踩一次就记住了。

二、绑定数据:从布局到代码

启用之后,布局文件要改一下。用<layout>标签把原来的布局包起来,再声明一个<data>节点:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.example.User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.age}" />
    </LinearLayout>
</layout>

看到@{user.name}了吗?这就是DataBinding的绑定语法。它会自动把User对象的name属性显示到TextView上。

然后在Activity里,这样用:

ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
User user = new User("张三", 28);
binding.setUser(user);

你想想看,以前要写findViewById,再setText,现在一行搞定。代码干净多了。

小提示:生成的Binding类名是根据布局文件名来的。比如activity_main.xml,对应的就是ActivityMainBinding。命名规则就是首字母大写,去掉下划线。

三、双向绑定:数据变了,UI跟着变;UI变了,数据也跟着变

单向绑定是数据驱动UI,双向绑定就是UI也能反过来改数据。最典型的场景就是EditText。

先让User类支持双向绑定,需要继承BaseObservable:

public class User extends BaseObservable {
    private String name;
    private int age;

    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }

    @Bindable
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        notifyPropertyChanged(BR.age);
    }
}

布局里用@={}语法:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={user.name}" />

注意是@={},多了一个等号。这就是双向绑定的标志。用户输入什么,user.name就变成什么。反过来,如果代码里改了user.name,EditText也会更新。

注意:双向绑定一定要配合BaseObservable或者LiveData使用。我曾经见过有人直接用普通Java对象,结果UI改了数据没反应——说白了就是没通知观察者。

四、BindingAdapter:自定义属性绑定

有时候系统自带的属性不够用,比如你想给ImageView加载网络图片。这时候BindingAdapter就派上用场了。

写一个静态方法,加上@BindingAdapter注解:

public class ImageBindingAdapter {
    @BindingAdapter("imageUrl")
    public static void loadImage(ImageView view, String url) {
        Glide.with(view.getContext())
                .load(url)
                .into(view);
    }
}

布局里直接这样用:

<ImageView
    android:layout_width="100dp"
    android:layout_height="100dp"
    app:imageUrl="@{user.avatar}" />

你看,自定义属性imageUrl就生效了。Glide会自动加载图片。我个人习惯把所有的BindingAdapter放在一个单独的类里,方便管理。

还可以传多个参数:

@BindingAdapter(value = {"imageUrl", "placeholder"}, requireAll = false)
public static void loadImage(ImageView view, String url, Drawable placeholder) {
    Glide.with(view.getContext())
            .load(url)
            .placeholder(placeholder)
            .into(view);
}

requireAll = false表示这两个参数不一定都要传,缺一个也能用。

五、知识体系总览

下面这张图,把DataBinding的核心脉络画出来了。你看一眼就能明白各个部分的关系:

DataBinding 核心知识体系 DataBinding 启用DataBinding 绑定数据 双向绑定 BindingAdapter buildFeatures <layout> 标签 @={} 语法 BaseObservable @BindingAdapter 注解 四个核心模块:启用 → 绑定 → 双向 → 自定义

六、避坑指南

我做了这么多年Android,DataBinding的坑也踩了不少。给你列几个常见的:

  • 布局文件名不能有特殊字符——Binding类是根据文件名生成的,如果文件名里有数字开头或者特殊符号,编译直接报错。
  • 变量名不要用关键字——比如nametype这些,虽然能用,但容易和系统属性冲突。我建议统一加个前缀,比如userNameuserType
  • 双向绑定一定要有getter和setter——而且getter上要加@Bindable,setter里要调notifyPropertyChanged。少一个都不行。
  • BindingAdapter方法必须是静态的——这个我一开始也犯过错,写成实例方法,结果死活不生效。
核心总结:DataBinding不是银弹,但它能帮你省掉大量模板代码。我个人建议中小型项目直接用,大型项目配合MVVM使用效果更好。记住四个关键词:启用、绑定、双向、自定义。把这四个点吃透了,DataBinding就算入门了。

好了,这一章的内容就到这里。代码不多,但都是实战里天天用的。你回去把项目里的findViewById都换成DataBinding试试,感受一下什么叫「清爽」。


公众号:蓝海资料掘金营,微信deep3321