Android架构探究之MVC设计模式: 点击阅读
Android架构探究之MVP设计模式: 点击阅读
Data Binding 是Android的JetPack其中的一个库,它可以让你的xml布局文件中的UI组件和你的data数据资源以声明的形式进行绑定,而且不是通过程序化书写代码的方式。
需求:
- 一个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,代码显得十分臃肿。
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 Binding的实现方法,以及为什么不用在activity里绑定xml内的控件id就可以更新ui。
build.gradle
中的android
结构下添加 dataBinding
android {
...
dataBinding {
enabled = true
}
}
作为根布局元素的开头,并配合
。为了快速改变xml布局,我们可以选中默认xml中生成的根布局元素,查看Show Context activity
右键点击convert to data binding layout
“@{ }”
语法写入特性属性中。在我们的例子中,有一个TextView需要展示被添加的学生的姓名,另一个TextView需要展示总学生人数。通过
android:text="@{studentbean.name}"
语句,我们将数据源学生bean类里的name数据与textview进行了绑定。与此同时在bean类,我们需提供一个公共的getName()
的方法,才可以使得xml组件获取到对象数据源内的数据
mainActivity
使用ActivityMainBinding
去绑定我们的xml文件就可以了,代码在上方已经列出来过。public class viewClickHandlers {
/**
* 处理绑定的view点击事件回调
*/
public void onBtnClick(View view){
}
}
<import type="com.yfz.mvvm_databinding.MainActivity.ViewClickHandlers"></import>
<variable
name="viewclickhandlers"
type="ViewClickHandlers" />
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();
}
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
}
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" />
中定义的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)}"
@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>
可观察性是指一个对象将其数据变化告知其他对象的能力。通过数据绑定库,您可以让对象、字段或集合变为可观察。
.
任何 plain-old 对象都可用于数据绑定,但修改对象不会自动使界面更新。通过数据绑定,数据对象可在其数据发生更改时通知其他对象,即监听器。可观察类有三种不同类型:对象、字段和集合。
.
当其中一个可观察数据对象绑定到界面并且该数据对象的属性发生更改时,界面会自动更新。
mBinding.setStudentbean(studentBean); //更新绑定的data variables
mBinding.setStudentmodel(mStudentModel); //更新绑定的data variables
我们需要提前将数据对象与视图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();
}
}
@Bindable
去观察类里的每个变量和notifyPropertyChanged
通知更新。所以我们可以使用ObservableFields
直接声明变量,当变量有变化时会自动通知UI更新。ObservableFields
可以看作是对@Bindable和notifyPropertyChanged封装public class StudentBeanFiled {
public ObservableField<String> name = new ObservableField<>();
public ObservableField<String> getName(){
return name;
}
}
@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>
/**
* 处理绑定的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);
}
1.我更改了activity文件的位置,在其外面套了一层文件夹(oneWayBind)后,原来写在activity里的类在xml报红例如(ViewClickHandlers)。解决办法就是
时,写入更详细的位置即可。
<import type="com.yfz.mvvm_databinding.oneWayBind.activity.MainActivity.ViewClickHandlers" />
QQ 交流群 723592501
[1]* 百度文献
[2]* 参考文章
[3]* Android 官网对于DataBinding的介绍,需fan.g墙阅览:点击查看