一:概述
DataBinding 是谷歌Google发布的一个数据绑定框架,基于MVVM 模式,用于降低布局和逻辑的耦合性,使代码逻辑更加清晰(MVVM 相对于 MVP,其实就是将 Presenter 层替换成了 ViewModel 层)(但其IDE支持不完美,报错信息不直接,不支持重构)。但是最后要补充一句,使用DataBinding时,一定要注意命名的规范(我曾经因为忽略命名问题,导致调了一天的Bug,好惨,我好辣鸡)
- 去掉Activity和Fragments的UI代码
- XML变成UI的唯一来源
- 不需要findViewById的步骤
- 数据能够单向或双向绑定到 layout 文件中
- 有助于防止内存泄漏
- 自动进行空检测以避免空指针异常
- 保证执行在主线程
- MVVM:
二:添加DataBinding
1.Gradle的添加
android {
...
dataBinding {
enabled = true
}
}
2.在XML布局文件最外层套上<layout></layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.administrator.databindingtest.MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="test"/>
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="test"/>
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="test"/>
</LinearLayout>
</layout>
三.测试
关于命名规则:
- 对于layout文件,首字母大写,去掉_改其后的首字母为大写,然后末尾添加Binding
- 对于view的ID,类似于layout规则,但是首单词字母不大写
- (注意:对于data class的引入,需要的是具有可观察性的data class:一种是实现Observable,第二种是实现LiveData(此相对于Observable更好用(个人认为,因为它能于DataBinding很好的结合)))
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*setContentView(R.layout.activity_main);*/
ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
binding.button.setText("测试点击");
binding.textView.setText("测试textview");
}
UI和事件的绑定:
数据的绑定:
在XML中添加数据
<data>
<variable
name="employee"
type="com.example.databindingtest.Employee"/>
<!--type中添加了自定义的Employee的类-->
</data>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{employee.firstname}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{employee.lastname}"/>
在MainActivity中调用:
Employee employee = new Employee("shazi", "haha");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*setContentView(R.layout.activity_main);*/
ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
/*binding.button.setText("测试点击");
binding.tVFirst.setText("测试textview");*/
binding.setEmployee(employee);
}
事件的绑定:(方法引用和监听器绑定两种方法)
方法引用:
先定义一个内部类class:
public class Presenter {
public void onTextPresenter(CharSequence s, int start, int before, int count){
employee.setFirstname(s.toString());
employee.setLastname(s + "woshilastname");
binding.setEmployee(employee);
}
public void onClick(View view){
Toast.makeText(MainActivity.this, "点击了此组件!!!", Toast.LENGTH_SHORT).show();
}
}
重复之前的步骤:
<variable
name="presenter"
type="com.example.databindingtest.MainActivity.Presenter" />
<EditText
android:textSize="25dp"
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="test"
android:onTextChanged="@{presenter.onTextPresenter}"/>
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="test"
android:onClick="@{presenter.onClick}"/>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*setContentView(R.layout.activity_main);*/
binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
/*binding.button.setText("测试点击");
binding.tVFirst.setText("测试textview");*/
binding.setEmployee(employee);
binding.setPresenter(new Presenter());
}
监听器绑定:
在Presenter类中添加:
public void onClickListenerBinding(Employee employee){
Toast.makeText(MainActivity.this, employee.getFirstname()
+ " " + employee.getLastname(), Toast.LENGTH_SHORT).show();
}
<Button
android:id="@+id/button_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="事件监听器"
android:onClick="@{() -> presenter.onClickListenerBinding(employee)}"/>
相对来说,监听器绑定灵活性更高,但是二者兼有所长,所以对于不同场合使用不同的绑定方法。
双向绑定:
DataBinding当ViewMoel层发生变化时,可以通过以上方法进行对View的自动更新。但是者仅仅时单项绑定,对于可输入(写)View(eg:EditText等),View更新之后却无法自动同步到ViewModel层。如果让ViewModel层持有View层的引用也可完成数据的同步。但是双向绑定的优点在于当View层数据更新之后,自动更新ViewModel层的数据,无需ViewModel持有View的引用,进一步解耦。
实现方法:@={表达式}
注意:当使用双向绑定时,涉及到绑定的变量对于其可见性有要求,只能是public(我曾经因为使用private而导致双向绑定失败,在overflow上得到解答,但是不知道有没有其他的解决方法,望大家知道的可以分享)
四:原理的认识
- android.binding
流程:开始编译--》处理layout文件--》解析表达式--》java编译--》依赖解析--》找到setter
- BR
- xxxBinding
其他详细信息可以查看官网guides(Data Binding Library)