Android架构探究之Data Binding数据绑定库基本使用
- 0. 本篇是探究数据绑定库Data Binding,提前为MVVM设计模式的探究做好准备。Android中实现MVC和MVP可在以下链接中阅读
- 1. 什么是Data Binding?
- 2. 举例说明,对比传统的方式和data binding
- 3. Data Binding的实现方法
- 5. Data Binding绑定xml控件的点击监听器/事件处理
- 6. Data Binding绑定点击事件时,传递参数 或 传入其他控件的对象
- 7. Data Binding也可以绑定方法 java Function
- 8. Data Binding使用可观察的数据对象更新UI
- 9. 使用 ObservableFields 更新 UI
- 10. 遇到的问题记录
- 5. Android技术生活交流
- Data Binding Github项目地址: 点击跳转
0. 本篇是探究数据绑定库Data Binding,提前为MVVM设计模式的探究做好准备。Android中实现MVC和MVP可在以下链接中阅读
1. 什么是Data Binding?
Data Binding 是Android的JetPack其中的一个库,它可以让你的xml布局文件中的UI组件和你的data数据资源以声明的形式进行绑定,而且不是通过程序化书写代码的方式。
2. 举例说明,对比传统的方式和data binding
需求:
- 一个EditView输入学生姓名。
- 一个Button点击后,将输入的姓名作为学生,创建一个学生对象,并将改学生对象储存至学生List中。
- 两个TextView,一个用来展示被添加学生的信息,一个用来展示当前学生人数
学生Bean类:
/**
* 学生Bean
*/
public class StudentBean {
private String name;
public StudentBean(String studentName){
this.name = studentName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 传统布局实现需求:
我们可以看到在对数据进行处理后,我们仍需在activity通过findViewById里获取两个TextView的控件id才可以更新视图UI,那么当布局非常多的时候,就会出现非常多的findViewById,代码显得十分臃肿。
- 使用Data Binding实现需求:
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding mBinding;
private EditText vEdtName;
private Button vBtnAdd;
private StudentModel mStudentModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main); //将其替换
mBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
initial();
addListener();
}
private void initial(){
mStudentModel = new StudentModel();
vEdtName = findViewById(R.id.vEdtName);
vBtnAdd = findViewById(R.id.vBtnAdd);
}
private void addListener(){
vBtnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
StudentBean studentBean = new StudentBean(vEdtName.getText().toString().trim());
mStudentModel.addStudentToList( studentBean );
mBinding.setStudentbean(studentBean); //更新绑定的data variables
mBinding.setStudentmodel(mStudentModel); //更新绑定的data variables
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.yfz.mvvm_databinding.bean.StudentBean"></import>
<variable
name="studentbean"
type="StudentBean" />
<import type="com.yfz.mvvm_databinding.model.StudentModel"></import>
<variable
name="studentmodel"
type="StudentModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="24dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/vEdtName"
android:hint="输入学生名字"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></EditText>
<Button
android:id="@+id/vBtnAdd"
android:text="添加学生"
app:layout_constraintTop_toBottomOf="@+id/vEdtName"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
<TextView
android:id="@+id/vTvDisplayName"
android:text="@{studentbean.name}"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
<TextView
android:id="@+id/vTvDisplayAmount"
android:text="@{String.valueOf(studentmodel.studentAmount)}"
app:layout_constraintTop_toBottomOf="@+id/vTvDisplayName"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
我们通过对比可以发现StudentBean 和 StudentModel没有变化,只有MainActivity和XMl文件有所变化。我们会发现在MainActivity里没有绑定xml中的textview视图,而且发现在xml布局中多了
<data><import><variable>
这三样东西。 下面就详细探究下Data Binding的实现方法,以及为什么不用在activity里绑定xml内的控件id就可以更新ui。
3. Data Binding的实现方法
- 1.在项目module的
build.gradle
中的android
结构下添加dataBinding
android {
...
dataBinding {
enabled = true
}
}
- 2.回到xml布局文件中,我们必须使用
<layout>
作为根布局元素的开头,并配合<data> <variable>
。为了快速改变xml布局,我们可以选中默认xml中生成的根布局元素,查看Show Context activity
右键点击convert to data binding layout
.
.
- 3.在布局中的表达式使用
“@{ }”
语法写入特性属性中。在我们的例子中,有一个TextView需要展示被添加的学生的姓名,另一个TextView需要展示总学生人数。
.
通过
android:text="@{studentbean.name}"
语句,我们将数据源学生bean类里的name数据与textview进行了绑定。与此同时在bean类,我们需提供一个公共的getName()
的方法,才可以使得xml组件获取到对象数据源内的数据
- 4.添加完成后我们需要clean 然后 rebuild project,这样系统就会自动生成必要的绑定类了。最后我们在
mainActivity
使用ActivityMainBinding
去绑定我们的xml文件就可以了,代码在上方已经列出来过。
5. Data Binding绑定xml控件的点击监听器/事件处理
- 1.在上述中我们发现,我们还是在mainActivity使用了FindViewById处理了Button的点击事件。可是Data Binding的存在不就是为了消除程序化绑定xml的控件吗?接下来我们就继续探究Data Binding,组件的点击事件或其他事件也是可以绑定的。
- 2.要绑定该类事件,需要提前在xml对应绑定的activity中(MainActivity)里写好一个回调类
public class viewClickHandlers {
/**
* 处理绑定的view点击事件回调
*/
public void onBtnClick(View view){
}
}
- 3.同时为了我们能够在xml里进行绑定该类对象,我们需要在xml里进行定义 data, variable
<import type="com.yfz.mvvm_databinding.MainActivity.ViewClickHandlers"></import>
<variable
name="viewclickhandlers"
type="ViewClickHandlers" />
- 4.在xml视图绑定后,我们还需要在MainActivity已经实例化该回调类对象,并将其对象赋值传入给
ActivityMainBinding
就完成了事件绑定。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
ViewClickHandlers mViewClickHandlers = new ViewClickHandlers();
mBinding.setViewclickhandlers(mViewClickHandlers);
initial();
}
6. Data Binding绑定点击事件时,传递参数 或 传入其他控件的对象
-
1.在上述中,我们在MainActivity里又
消除了一个Button的FindViewById
,那么我们还剩下一个EditText的FindViewById
存在MainActivity,让我们继续探究。 -
2.当我们点击按钮时,需要通过控件EditText获取到输入的学生姓名。既然我们已经绑定了点击事件,那么在触发回调类的时候传入该EditText控件对象不就能够获取学生姓名了。
-
3.改写一下我们之前在MainActivity里定义好的点击事件回调类
/**
* 处理绑定的view点击事件回调,同时也传递editText对象
*/
public void onBtnClickWithEditText(View view, EditText editText){
StudentBean studentBean = new StudentBean(editText.getText().toString().trim());
mStudentModel.addStudentToList( studentBean );
mBinding.setStudentbean(studentBean); //更新绑定的data variables
mBinding.setStudentmodel(mStudentModel); //更新绑定的data variables
}
- 4.使用
lambda表达式
,在xml改写onClick绑定事件,vEdtName为定义的EditText的id
<Button
android:id="@+id/vBtnAdd"
android:text="添加学生"
android:onClick="@{(v) -> viewclickhandlers.onBtnClickWithEditText(v,vEdtName)}"
app:layout_constraintTop_toBottomOf="@+id/vEdtName"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
- 5.那么不光是xml里的对象可以传入,在
<data>中定义的StudentBean数据对象
也是可以进行参数传递。
/**
* 处理绑定的view点击事件回调,同时也传递studentBean对象
*/
public void onBtnClickWithStudentBean(View view, StudentBean studentBean){
mStudentModel.addStudentToList( studentBean );
mBinding.setStudentbean(studentBean); //更新绑定的data variables
mBinding.setStudentmodel(mStudentModel); //更新绑定的data variables
}
android:onClick="@{(v) -> viewclickhandlers.onBtnClickWithStudentBean(v,studentbean)}"
7. Data Binding也可以绑定方法 java Function
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
……
……
//绑定方法
mBindFunction = new BindFunction();
mBinding.setBindfunction(mBindFunction);
……
……
}
/**
* 绑定方法
*/
public static class BindFunction{
public String getAmount(StudentModel studentModel) {
return "绑定方法,获取当前的学生人数为:"+studentModel.getStudentAmount();
}
}
<import type="com.yfz.mvvm_databinding.MainActivity.BindFunction"</import>
<variable
name="bindfunction"
type="BindFunction" />
……
……
……
<TextView
android:id="@+id/vTvBindFunction"
android:text="@{bindfunction.getAmount(studentmodel)}"
app:layout_constraintTop_toBottomOf="@+id/vTvDisplayAmount"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</TextView>
8. Data Binding使用可观察的数据对象更新UI
- 1.什么是 可观察的数据对象
可观察性是指一个对象将其数据变化告知其他对象的能力。通过数据绑定库,您可以让对象、字段或集合变为可观察。
.
任何 plain-old 对象都可用于数据绑定,但修改对象不会自动使界面更新。通过数据绑定,数据对象可在其数据发生更改时通知其他对象,即监听器。可观察类有三种不同类型:对象、字段和集合。
.
当其中一个可观察数据对象绑定到界面并且该数据对象的属性发生更改时,界面会自动更新。
- 2.在上述中我们成功的消除了在MainActivity中的findViewById。那么我们虽然将xml与数据进行绑定了,但是更新UI的途径还是需要我们主动调用mBinding的setter方法,传入新的数据才可以刷新。
mBinding.setStudentbean(studentBean); //更新绑定的data variables
mBinding.setStudentmodel(mStudentModel); //更新绑定的data variables
- 3.为了实现观察者,
我们需要提前将数据对象与视图UI进行绑定
,并将数据对象内提供的公共方法添加注解@Bindable
。当更新数据对象的数据时后调用notifyPropertyChanged(BR.*****)
方法即可。( ****的方法名,是我们在公共方法的地方添加注解后,rebuild后自动生成的。)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
mViewClickHandlers = new ViewClickHandlers();
mBinding.setViewclickhandlers(mViewClickHandlers);
//****提前绑定数据对象
mStudentBean = new StudentBean("小明");
mBinding.setStudentbean(mStudentBean); //绑定一个学生Bean
mStudentModel = new StudentModel();
mStudentModel.addStudentToList( mStudentBean );
mBinding.setStudentmodel(mStudentModel); //绑定一个学生Model
//*****
initial();
}
……
……
……
public void onBtnClickWithEditText(View view, EditText editText){
String name = editText.getText().toString().trim();
mStudentBean.setName(name);
mStudentModel.addStudentToList( mStudentBean );
// StudentBean studentBean = new StudentBean(editText.getText().toString().trim()); //废弃
// mBinding.setStudentbean(studentBean); //废弃
// mStudentModel.addStudentToList( studentBean ); //废弃
// mBinding.setStudentmodel(mStudentModel); //废弃
}
/**
* 学生Bean
*/
public class StudentBean extends BaseObservable {
String name;
public StudentBean(String studentName){
this.name = studentName;
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
}
public class StudentModel extends BaseObservable {
List<StudentBean> mStudentList = new ArrayList<>();
/**
* 将学生对象添加至list中
* @param studentBean
*/
public void addStudentToList(StudentBean studentBean){
mStudentList.add(studentBean);
//studentAmount是通过方法 getStudentAmount 添加了Bindable注解后自动生成的。
notifyPropertyChanged(BR.studentAmount);
}
/**
* 返回学生数量
* @return
*/
@Bindable
public int getStudentAmount(){
return mStudentList.size();
}
}
9. 使用 ObservableFields 更新 UI
- 1.在上述中我们实现了可观察者自动更新UI的方法,但是如果studentBean里有许多学生的属性数据都要监听,那要添加非常多的
@Bindable
去观察类里的每个变量和notifyPropertyChanged
通知更新。所以我们可以使用ObservableFields
直接声明变量,当变量有变化时会自动通知UI更新。ObservableFields
可以看作是对@Bindable和notifyPropertyChanged封装 - 2.为了不与之前的StudentBean类冲突,我们重新写个类去实现fileds方法
public class StudentBeanFiled {
public ObservableField<String> name = new ObservableField<>();
public ObservableField<String> getName(){
return name;
}
}
- 3.同时将其实例化并绑定至layout中,并在xml里声明,且与新创建的textview绑定
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
……
//绑定filed
mStudentBeanFiled = new StudentBeanFiled();
mBinding.setStudentbeanfiled(mStudentBeanFiled);
……
}
<data>
……
……
<import type="com.yfz.mvvm_databinding.bean.StudentBeanFiled"></import>
<variable
name="studentbeanfiled"
type="StudentBeanFiled" />
<data>
……
……
<TextView
android:text="@={studentbeanfiled.name}"
app:layout_constraintTop_toBottomOf="@+id/vBtnAdd"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="20dp"
android:textColor="#FFED2E"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
- 4.在我们之前写的添加按钮事件里,进行赋值。注意这里我们使用的是 setter方法
/**
* 处理绑定的view点击事件回调,同时也传递editText对象
*/
public void onBtnClickWithEditText(View view, EditText editText){
// String name = editText.getText().toString().trim();
// mStudentBean.setName(name); //可观察者绑定变量
// mStudentModel.addStudentToList( mStudentBean ); //可观察者绑定变量
//--使用ObservableField声明变量后,用setter方法赋值
mStudentBeanFiled.name.set(name);
}
- Data Binding Github项目地址: 点击跳转
10. 遇到的问题记录
1.我更改了activity文件的位置,在其外面套了一层文件夹(oneWayBind)后,原来写在activity里的类在xml报红例如(ViewClickHandlers)。解决办法就是<import>
时,写入更详细的位置即可。
<import type="com.yfz.mvvm_databinding.oneWayBind.activity.MainActivity.ViewClickHandlers" />
5. Android技术生活交流
QQ 交流群 723592501
[1]* 百度文献
[2]* 参考文章
[3]* Android 官网对于DataBinding的介绍,需fan.g墙阅览:点击查看