DataBinding是Jetpack中比较受非议的一个库,很多开发者不习惯且不喜欢在xml布局中进行java层代码的数据绑定,如果是简单的页面,用不上databinding,而复杂的页面,用了databinding对后续的问题排查又是个蛋疼的事,但不妨碍学习databinding的使用。
优点:
1,UI控件的代码在布局中编写,降低页面与布局文件的耦合度
2,不需要写findviewById(viewbinding表示它也可以)
3,布局文件可以包含简单的业务逻辑(个人不建议)
使用基本操作
1,在app的adle文件中开启数据绑定功能
android {...dataBinding{enabled = true}
}
2,修改布局文件
将光标移到根目录,会出现小灯泡,点击,选择 Convert to data binding layout(转变为databinding布局)
自动生成如下内容
l<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android=""xmlns:tools=""><data></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/tv_message"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World,I am databinding !" /></LinearLayout>
</layout>
也可以手动添加<layout> <data>等标签转变布局
rebuild后会自动生成对应的binding类
3,使用绑定类
databinding protected void onCreate(Bundle savedInstanceState) {Create(savedInstanceState);ActivityMain6Binding activityMain6Binding = DataBindingUtil.setContentView(this, R.layout.activity_main6);activityMain6Binding.tvMessage.setText("hello,databinding");}另比较viewbinding的使用protected void onCreate(Bundle savedInstanceState) {Create(savedInstanceState);ActivityMain5Binding binding = ActivityMain5Binding.inflate(getLayoutInflater());Root());binding.tvMessage.setText("hello,viewbinding");}可以看出,viewbinding就是databinding的子类,底层也是databinding来实现的,数据绑定离不开识图的绑定
4,布局中设置变量并进行控件绑定
<?xml version="1.0" encoding="utf-8"?>
<layout //表示这是databinding的布局文件 xmlns:android=""xmlns:tools=""><data>//用于放置布局中控件所需要的变量<variablename="student"type="com.sun.databinding.Student" /><variablename="name"type="String" /><variablename="age"type="int" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><TextViewandroid:id="@+id/tv_message"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World,I am databinding !" /><TextViewandroid:id="@+id/tv_student_info"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String()}" /><TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{name}" /><TextViewandroid:id="@+id/tv_age"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String.valueOf(age)}" /></LinearLayout>
</layout>
5,将数据引入到布局中
@Overrideprotected void onCreate(Bundle savedInstanceState) {Create(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,布局中导入并引用
<data>...<import type="com.sun.databinding.StaticMethod" />
</data>3,调用静态方法<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{Name()}" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{Name(age)}" />
7,绑定点击事件
1,在页面中设置点击逻辑/*** 点击事件*/public class EventClick {private Context context;public EventClick(Context context) {t = context;}public void clickToast(View view) {Log.e(TAG, "view的id=" + Id() + " " + ((Button) view).getText());//id=-1,因为我没有设置idToast.makeText(context, "我通过 EventClick databind了", Toast.LENGTH_SHORT).show();}}2,在布局中使用添加EventClick的实例<data>...<variablename="eventClick"type="com.sun.databinding.MainActivity.EventClick" /></data>3,绑定到button的点击事件中<Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="@{eventClick.clickToast}" //或者 android:onClick="@{eventClick::clickToast}" android:text="按钮点击"/>
8,二级页面传值,所谓的二级页面其实是对布局中layout包裹的布局进行传值
1,二级页面简单编写
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android=""><data><variablename="studentinfo"type="com.sun.databinding.Student" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="我是layout布局" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String()}" /></LinearLayout>
</layout>2,添加二级布局,同时根据二级页面的变量进行传值
<includelayout="@layout/layout_common"app:studentinfo="@{student}" />//给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,布局显示
<data>...<variablename="student_observable"type="com.sun.databinding.StudentObservable" /></data><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:hint="输入框1"android:text="@={student_observable.name}" />//此处用@=,可接收属性的数据更改并同时监听用户更新<EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:hint="输入框2"android:text="@={student_observable.name}" />//此处用@=使用这种方法必须继承自BaseObservable成为被观察者,另外,在Getter方法添加@Bindable标签,在setting中进行notifyPropertyChanged(),也可以通过更简单的ObservableField<T>的方式实现双向绑定。
方法2(使用ObservableField<T>)
1,创建类
package com.sun.databinding;import androidx.databinding.ObservableField;public class StudentObservableField {//ObservableField可以看成是对BaseObservable,set,get, @Bindable,notify进行了封装//基本数据类型:ObservableInt,ObservableFloat等public ObservableField<String> name;public StudentObservableField(String name) {this.name = new ObservableField<String>(name);}}2,布局及使用同BaseObservable是一样的
<data>...<variablename="studentfield"type="com.sun.databinding.StudentObservableField" /></data><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:hint="输入框1"android:text="@={studentfield.name}" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:hint="输入框2"android:text="@={studentfield.name}" />
BaseObservable与ObservableField的比较:
看源码知道ObservableField是对BaseObservable进行了封装,站远一点分析,属性依附在对象中,BaseObservable作用在对象上,所以需要继承才能让内部的属性可以双向数据绑定,而ObservableField则作用在属性上,直接做了封装,所以类就不用做特殊处理显得更加简单。
至此,databinding的初步使用已经完成,如果再看官网的整个流程的话,还是有很多东西没有覆盖到的。虽然很多时候databinding在开发过程中饱受争议,但不妨碍我们学习使用它,内部的实现很多地方还是值得学习的。
这一篇只介绍使用,下一篇开始将深入接触bindingAdapter的使用和对databinding的源码分析。
Android-Jetpack代码位置:github
本文发布于:2024-02-02 07:37:35,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170683065642326.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |