阅读指南
简介
databinding,实现数据绑定的一种框架,可以降低Activity布局和逻辑的耦合性,省略传统的findViewById操作,节省代码,其中双向绑定,或者单项绑定的操作,可以大量减少传统赋值的代码,有效防止内存泄露,而且能自动规避空指针异常。
优势
- 省略findViewById()操作,且性能更优越,节省代码量
- 能根据数据变化即时更新layout中的控件
- 支持双向更新数据,用于适配器中可以简化刷新逻辑的代码
- 支持Bean中单个字段的更新,节省性能消耗
不足
- Xml中的代码过于繁琐,臃肿!
一、引用方式和Activity基础赋值
1.引入库
android {
dataBinding {
enabled = true
}
}
2.修改layout布局
其中Alt+回车键可以修改成databinding的布局格式
修改之后得结果如下:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>//用于声明要用到的变量以及变量类型
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TestActivity2">
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
3.新建一个Student对象
public class Student {
private int age;
private String name;
...省略get()、set()
}
4.并且在data标签中引用
<data>
//引用方式一
<variable
name="student"
type="com.example.datebindingdemo.Student" />
//引用方式二
<import type="com.example.datebindingdemo.Student"/>
<variable
name="student"
type="Student" />
//如果项目中有两个Student类,那么可以设置一个alisa别名作为区分
<import type="com.example.datebindingdemo.bean.Student" alias="Student2"/>
<variable
name="student2"
type="Student2" />
</data>
5.利用student对象给布局中的控件赋值
<androidx.constraintlayout.widget.ConstraintLayout
...>
<TextView
android:id="@+id/name_tv"
...
android:text="@{student.name,default=小米}"/>
//TextView 引用到相关的变量,DataBinding 会将之映射到相应的getter 方法
//default 属性可以用于设立默认值
<TextView
android:id="@+id/age_tv"
...
android:text="@{String.valueOf(student.age)}"/>
<TextView
android:id="@+id/other_tv"
android:text="" />
</androidx.constraintlayout.widget.ConstraintLayout>
6.设置数据源:
public class TestActivity2 extends AppCompatActivity {
Student student;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//摒弃原有的设置布局方式,通过DataBindingUtil设置
//setContentView(R.layout.activity_test2);
//ActivityTest2Binding是根据layout名字生成
ActivityTest2Binding activityMain2Binding = DataBindingUtil.setContentView(this, R.layout.activity_test2);
student = new Student();
student.setAge(10);
student.setName("小红");
activityMain2Binding.setStudent(student);
//代替findViewById()
activityMain2Binding.otherTv.setText("哈哈");
}
}
二、单向赋值
BaseObservable
Bean对象继承BaseObservable,通过notifyChange()和notifyPropertyChanged()实现单向赋值, addOnPropertyChangedCallback()方法用于监听赋值的变化:
public class Student extends BaseObservable {
//如果是 private 修饰符,则在成员变量的 get 方法上添加 @Bindable 注解
private int age;
//如果是 public 修饰符,则可以直接在成员变量上方加上 @Bindable 注解
@Bindable
public String name;
@Bindable
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
//只更新本字段,BR 的生成通过注释 @Bindable 生成,可以通过 BR notify 特定属性关联的视图
notifyPropertyChanged(BR.age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
//更新所有字段
notifyChange();
}
}
Activity中实现赋值逻辑:
Student student;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
ActivityTest2Binding activityMain2Binding = DataBindingUtil.setContentView(this, R.layout.activity_test2);
student = new Student();
activityMain2Binding.setStudent(student);
//对点击事件赋值
activityMain2Binding.setChange(new Change());
//实现了 Observable 接口的类允许注册一个监听器,当可观察对象的属性更改时就会通知这个监听器
student.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
@Override //propertyId用于识别字段
public void onPropertyChanged(Observable sender, int propertyId) {
if(propertyId==BR.age){
Log.e("改变的是age:",BR.age+"");
}else if(propertyId==BR.name){
Log.e("改变的是name:",BR.name+"");
}else if(propertyId==BR._all){
Log.e("全都改变了",BR._all+"");
}
}
});
}
//实现点击事件的方法类
public class Change{
public void changeAgeListener(){
student.setAge(100);
}
public void changeAll(