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,现在一行搞定。代码干净多了。
三、双向绑定:数据变了,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也会更新。
四、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的核心脉络画出来了。你看一眼就能明白各个部分的关系:
六、避坑指南
我做了这么多年Android,DataBinding的坑也踩了不少。给你列几个常见的:
- 布局文件名不能有特殊字符——Binding类是根据文件名生成的,如果文件名里有数字开头或者特殊符号,编译直接报错。
- 变量名不要用关键字——比如
name、type这些,虽然能用,但容易和系统属性冲突。我建议统一加个前缀,比如userName、userType。 - 双向绑定一定要有getter和setter——而且getter上要加
@Bindable,setter里要调notifyPropertyChanged。少一个都不行。 - BindingAdapter方法必须是静态的——这个我一开始也犯过错,写成实例方法,结果死活不生效。
好了,这一章的内容就到这里。代码不多,但都是实战里天天用的。你回去把项目里的findViewById都换成DataBinding试试,感受一下什么叫「清爽」。
公众号:蓝海资料掘金营,微信deep3321