https://www.jianshu.com/p/de4d50b88437
build.gradle 里添加
android{
dataBinding {
enabled = true
}
}
新建实体类UserBean实现BaseObservable:
public class UserBean extends BaseObservable{
private String name;
private String gender;
public final ObservableField<Integer> age = new ObservableField<>();
public UserBean(String name, String gender,int age) {
this.name = name;
this.gender = gender;
this.age.set(age);
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@Bindable
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
notifyPropertyChanged(BR.gender);
}
}
activity_databinding.xml中:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="userBean"
type="com.example.UserBean" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:text="@{userBean.name}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@{userBean.gender}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@{String.valueOf(userBean.age)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/uid_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</layout>
activity中:
ActivityDatabindingBinding databindingBinding = DataBindingUtil.setContentView(this, R.layout.activity_databinding);
UserBean userBean = new UserBean("张三","男",16);
databindingBinding.setUserBean(userBean);
databindingBinding.uidBtn.setOnClickListener((v)->{
userBean.setGender("女");
userBean.setName("李思");
userBean.age.set(18);
});
这里的ActivityDatabindingBinding是根据xml布局文件的名字自动生成的,比如xml叫xml_test.xml就会生成XmlTestBinding。
DataBinding主要解决了两个问题:
- 需要多次findViewById。
- 更新数据时需要切换至UI线程。当你的Activity需要展示新的数据时,你可以在后台线程中获取数据,然后直接交给DataBinding就可以了,完全不需要关心线程切换的问题。
DataBinding解决这些问题,就是针对每个activity布局,在编译阶段,生成一个viewDataBinding类的对象,该对象持有activity要展示的数据和布局中的各个view的引用,数据和展示的布局紧紧绑定在一起。
DataBinding背后做了什么
1.DataBinding会对根元素为<layout>的布局文件进行预处理,会对根元素和那些在属性中使用了binding表达式的view设置成Tag,而原有的<layout>标签<data><variable>和各个view中的binding表达式都不见了。DataBinding会把这些内容抽取出来生成一个activity_databinding-layout.xml文件。
2.生成ActivityDatabindingBinding类、ActivityDatabindingBindingImpl类与BR类,ActivityDatabindingBindingImpl中会生成对应xml文件里的view
// views
@NonNull private final android.widget.LinearLayout mboundView0;
@NonNull private final android.widget.TextView mboundView1;
@NonNull private final android.widget.TextView mboundView2;
@NonNull private final android.widget.TextView mboundView3;
生成的BR类
public class BR {
public static final int _all = 0;
public static final int gender = 1;
public static final int name = 2;
public static final int userBean = 3;
}
在实体类(继承了BaseObservable的)的属性的get方法中添加了@Bindable注解的才会在BR类中生成对应的变量,_all是自动生成的。
实际上,BR中的常量是一种标识符,它对应一个会发生变化的数据,当数据改变后,你可以用该标识符通知DataBinding,很快,DataBinding就会用新的数据去更新UI。
3.生成ActivityDatabindingBinding实例并绑定,
这里主要分三个步骤
①inflate处理后的布局文件得到一个viewgroup变量root,
②DataBindingUtil会将这个变量root传递给ActivityDatabindingBinding的构造方法,生成一个ActivityDatabindingBinding的实例,就是我们在onCreate方法中获取的binding对象,在构造方法中,ActivityDatabindingBinding会首先遍历root,根据各个View的Tag或者id,初始化自己的fields。至此,Tag们的历史使命完成了,ActivityDatabindingBinding将会把之前加到各个View上的Tags清空。
③构造方法调用invalidateAll引发数据绑定,ActivityDatabindingBinding将会计算各个view上的binding表达式,然后赋值给view相应的属性。
赋值的过程实际上就是binding表达式求值的过程,生成的binding类里的临时变量对应的并不是实体类中的成员变量,而是实体类中的成员变量的get方法。