Data Binding
优势
- MVVM
- 去掉Activity&Fragment内的UI代码
- 减少FindViewById代码的作用
- 类似方案 ButterKnife , Android Annotations ,Robo Binding
劣势
- IDE支持不完善
- 报错信息不直接
- 没有重构支持
配置
App Module的android标签内 开启:
android {
...
dataBinding{
enabled = true
}
}
基础语法
用法一 :去除findViewById
在原layout文件外套一层标签
<layout >
//原来的layout 命名空间上移
</layout>
//生成规则是根据布局文件来生成的 例:activity_main -> ActivityMainBinding
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); 替换掉setContentView(R.layout.activity_main)
这个时候就 不用findViewById来获取控件了,而是用Binding.xxxView 代替
用法二 : 去除fbi的同时设置初始数据
<layout >
<data>
<variable
name="employee"
type="net.hongqian.better.databingdemo.Employee"/>
</data>
//原来的layout 命名空间上移
</layout>
<LinearLayout>
<TextView
...
android:text="@{employee.name}" />
<TextView
...
android:text="@{employee.pwd}" />
</LinearLayout>
binding.setEmployee(Employee对象)或者
binding.setVariable(BR.employee,Employee对象); 都能达到同样效果
用法三 :UI/事件绑定
- Bind UI## setVariable ,setXXX
- 事件 onClick ,onLongClick ,onTextChanged ...
方法一:方法引用
<layout >
<data>
<variable
name="employee"
type="net.hongqian.better.databingdemo.Employee"/>
<variable
name="presenter" type="net.hongqian.better.databingdemo.MainActivity
.Presenter"/>
</data>
<LinearLayout>
<TextView
...
android:id="@+id/tv_name"
android:text="@{employee.name}"
android:onClick="@{presenter.onClicked}" />
<EditText
...
android:id="@+id/tv_pwd"
android:onTextChanged="@{presenter.onTextChanged}"/>
</LinearLayout>
</layout>
代码中使用
binding.setVariable(net.hongqian.better.databingdemo.BR.employee, employee);
binding.setPresenter(new Presenter());
public class Presenter {
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
employee.setName(charSequence.toString());
binding.setEmployee(employee); //重新设置一下employee
}
public void onClicked(View view) { //方法名可以不一样,但是参数要一样
Toast.makeText(MainActivity.this, "点击事件发生了!", Toast.LENGTH_SHORT).show();
}
}
方法二:监听器绑定语法 lamda表达式
<TextView
android:id="@+id/tv_name"
android:onClick="@{() ->presenter.onClickListenerBinding(employee)}" />
public class Presenter {
public void onClickListenerBinding(Employee employee){
Toast.makeText(MainActivity.this, employee.getName(), Toast.LENGTH_SHORT).show();
}
}
表达式
- 二元运算符 & | ^
- 一元运算符 + - ! ~
- 移位 >> >>> <<
- 比较 == > < >= <=
- Instanceof
- Grouping ()
- Cast
- Array [] 访问
- 三元运算符 ?
- this super new 显示泛型调用不支持
- 取非空表达式 android:text = "@{user.displayName ?? user.lastName}"
相当于 android:Text="@{user.displayName!=null ? user.displayName: user.lastName}" - 设置尺寸时可以这样写 @dimen + @dimen 将引入的dimen相加
Include
<include
layout="@layout/include_demo"
bind:employee="@{employee}"/>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="employee"
type="net.hongqian.better.databingdemo.Employee" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@{employee.name}" />
</FrameLayout>
</layout>
observable
一,baseObservable
使用Bindable注解的属性 当其发生变化时 会使相应的UI层发生变化:
我们需要在getter方法上添加Bindable注解后,Bindable注解会自动生成一个BR类,该类位于app module包下,通过BR类我们设置更新的数据,当Model中的数据发生变化时,setter方法中的notifyPropertyChanged()就会通知UI更新数据了。
public class Employee extends BaseObservable {
private String name;
private String pwd;
public Employee(String name, String pwd) {
this.name = name;
this.pwd = pwd;
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name); //通知
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
public class Presenter {
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
employee.setName(charSequence.toString());
}
<layout >
<data>
<variable
name="employee"
type="net.hongqian.better.databingdemo.Employee" />
<import type="android.view.View"/> //引入类型
</data>
<FrameLayout
android:visibility="@{employee.getIsFired? View.GONE:View.VISIBLE}" //使用引入的类型
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@{employee.name}" />
</FrameLayout>
</layout>
方法名要使用getXXX() setXXX()这样的 不然编译会报错
private boolean isFired;
@Bindable
public boolean getIsFired() {
return isFired;
}
public void setFired(boolean fired) {
isFired = fired;
notifyPropertyChanged(BR.isFired);
}
二,Observable Fields
我们刚刚介绍的通知UI更新的方法是用User类继承自BaseObservable,然后在getter上添加注解、在setter中添加notify方法,这感觉总是有点麻烦,步骤繁琐,于是,Google推出ObservableFields类,使用它我们可以简化我们的Model类
private ObservableBoolean isFired=new ObservableBoolean(); //创建对象
public boolean getIsFired() {
return isFired.get();
}
public void setFired(boolean fired) {
isFired.set(fired);
notifyChange();
}
应用:
employee.setFired(!employee.getIsFired());
三,Observable Collection
包括 ObservableArrayMap ,ObservableArrayList
public ObservableArrayMap<String,String> map=new ObservableArrayMap<String, String>();
public Employee(String name, String pwd) {
this.name = name;
this.pwd = pwd;
isFired.set(false);
map.put("hello","word");
map.put("hi","word1");
map.put("hi","word2");
}
<TextView
...
android:text='@{employee.map["hello"]}'
/>