DataBinding是Jetpack中比较受非议的一个库,很多开发者不习惯且不喜欢在xml布局中进行java层代码的数据绑定,如果是简单的页面,用不上databinding,而复杂的页面,用了databinding对后续的问题排查又是个蛋疼的事,但不妨碍学习databinding的使用。
优点:
1,UI控件的代码在布局中编写,降低页面与布局文件的耦合度
2,不需要写findviewById(viewbinding表示它也可以)
3,布局文件可以包含简单的业务逻辑(个人不建议)
使用基本操作
1,在app的build.gradle文件中开启数据绑定功能
android {
...
dataBinding{
enabled = true
}
}
2,修改布局文件
将光标移到根目录,会出现小灯泡,点击,选择 Convert to data binding layout(转变为databinding布局)
自动生成如下内容
activity_main6.xml
也可以手动添加
3,使用绑定类
databinding
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMain6Binding activityMain6Binding = DataBindingUtil.setContentView(this, R.layout.activity_main6);
activityMain6Binding.tvMessage.setText("hello,databinding");
}
另比较viewbinding的使用
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMain5Binding binding = ActivityMain5Binding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
binding.tvMessage.setText("hello,viewbinding");
}
可以看出,viewbinding就是databinding的子类,底层也是databinding来实现的,数据绑定离不开识图的绑定
4,布局中设置变量并进行控件绑定
//用于放置布局中控件所需要的变量
5,将数据引入到布局中
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMain6Binding activityMain6Binding = DataBindingUtil.setContentView(this, R.layout.activity_main6);
activityMain6Binding.tvMessage.setText("hello,databinding");
//第一种方式(个人推荐这种方式,这种方式可以强制设置属性的类型,避免很多传参问题,同时也不会把其他布局的变量进行设置)
activityMain6Binding.setAge(12);//传入整型时会默认为资源id,要进行二次处理
activityMain6Binding.setName("sunguanyong");
activityMain6Binding.setStudent(new Student("hanmeimei", 14));
//第二种方式(BR类似于项目的R文件,管理所有布局变量的id,这里必须传入正确的id才能传好数据,而且无法跳转到布局中的变量位置,所以不推荐)
activityMain6Binding.setVariable(BR.age, 12);
activityMain6Binding.setVariable(BR.name, "sunguanyong");
//activityMain6Binding.setVariable(BR.name1, "sunguanyong");//这个name1是另一个布局中的变量,也能进行设置操作,这就很容易引起错误,实际不会崩溃,但没有作用
activityMain6Binding.setVariable(BR.student, new Student("hanmeimei", 15));
}
这样,最基本的databinding的使用已经完成,下面拓展别的用法。
6,布局中绑定静态方法
1,静态方法
package com.sun.databinding;
public class StaticMethod {
public static String getName() {
return "sunguanyong 2022";
}
public static String getName(int age) {
return "hello ,lilei ," + age;
}
}
2,布局中导入并引用
...
3,调用静态方法
7,绑定点击事件
1,在页面中设置点击逻辑
/**
* 点击事件
*/
public class EventClick {
private Context context;
public EventClick(Context context) {
this.context = context;
}
public void clickToast(View view) {
Log.e(TAG, "view的id=" + view.getId() + " " + ((Button) view).getText());//id=-1,因为我没有设置id
Toast.makeText(context, "我通过 EventClick databind了", Toast.LENGTH_SHORT).show();
}
}
2,在布局中使用添加EventClick的实例
...
3,绑定到button的点击事件中
8,二级页面传值,所谓的二级页面其实是对布局中layout包裹的布局进行传值
1,二级页面简单编写
2,添加二级布局,同时根据二级页面的变量进行传值
//给studentinfo的变量传入值,值为页面传来的student
上面的数据绑定操作都是单向操作,页面更改数据从而导致布局显示变化,也可以实现双向绑定。
9,要想实现双向绑定,肯定离不开观察者模式,双向绑定也是这一模式的具体体现
方法1(使用BaseObservable)
1,建立 被观察类
public class StudentObservable extends BaseObservable {
public String name;
public StudentObservable(String name) {
this.name = name;
}
@Bindable //告诉编译器,对这个字段进行双向绑定
public String getName(){
return name;
}
public void setName(String name){//数据发生变化时自动调用,也可以主动调用
if(!TextUtils.isEmpty(name)&&!this.name.equals(name)){
this.name=name;
notifyPropertyChanged(BR.name);//使用BaseObservable中的notifyPropertyChanged(BR.id)进行通知
}
}
}
2,布局显示
...
//此处用@=,可接收属性的数据更改并同时监听用户更新
//此处用@=
使用这种方法必须继承自BaseObservable成为被观察者,另外,在Getter方法添加@Bindable标签,在setting中进行notifyPropertyChanged(),也可以通过更简单的ObservableField的方式实现双向绑定。
方法2(使用ObservableField
1,创建类
package com.sun.databinding;
import androidx.databinding.ObservableField;
public class StudentObservableField {
//ObservableField可以看成是对BaseObservable,set,get, @Bindable,notify进行了封装
//基本数据类型:ObservableInt,ObservableFloat等
public ObservableField name;
public StudentObservableField(String name) {
this.name = new ObservableField(name);
}
}
2,布局及使用同BaseObservable是一样的
...
BaseObservable与ObservableField的比较:
看源码知道ObservableField是对BaseObservable进行了封装,站远一点分析,属性依附在对象中,BaseObservable作用在对象上,所以需要继承才能让内部的属性可以双向数据绑定,而ObservableField则作用在属性上,直接做了封装,所以类就不用做特殊处理显得更加简单。
至此,databinding的初步使用已经完成,如果再看官网的整个流程的话,还是有很多东西没有覆盖到的。虽然很多时候databinding在开发过程中饱受争议,但不妨碍我们学习使用它,内部的实现很多地方还是值得学习的。
这一篇只介绍使用,下一篇开始将深入接触bindingAdapter的使用和对databinding的源码分析。
Android-Jetpack代码位置:github