DataBinding简单使用
本篇文章介绍DataBinding的使用,其故名思义,数据绑定,它可以绑定数据到xml,并实现自动刷新.它有效率高,性能强,功能强等特点.本篇文章大多译自安卓官方文档结合自己使用中的粗浅认识,水平有限,难免出错,亲们可直接查看官方文档或者推荐markzhai的博客.(文尾有链接)
那么如何使用Data Bingding Library(数据绑定库)来编写声明式布局以及用尽量少的代码来绑定程序的布局和逻辑呢.
1 Build Environment 构建环境
此库灵活性强,兼容性强,可以兼容到Android2.1,想使用此库,Gradle插件要1.5.0-alpha1或更高.
若使用Android Studio,可在build.gradle文件中添加
android {
….
dataBinding {
enabled = true
}
}
根据gradle文件重新编译项目后,即可使用此库.
2 简单使用 Data Binding Layout Files 数据绑定界面文件
数据绑定界面与非数据绑定界面(平常界面)有轻微不同,它的跟标签是layout,然后是data标签和view跟标签。这个view跟标签就是你在平常界面中的跟标签。简单使用如下:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
</layout>
data标签下定义的变量名user可以代表User实体类,则在LinearLayout下可以使用user的属性.语法是
@{}
User类如下:
public class User {
public final String firstName;
public final String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
也可以这样定义User
public class User {
private final String firstName;
private final String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
}
以上的俩个类对于Data Binding而言是等价的,@{user.firstName}会去访问第一个User类的firstName属性以及第二个User类的getFirstName()方法.
Binding Data 数据绑定
通常,一个Binding类会根据布局文件生成,命名规则是首字母大写并添加”Binding”的后缀.比如一个xml文件
main_activity.xml 会生成类MainActivityBinding. 此类包含所有布局里绑定的属性(the user variable)而且它指定如何根据binding表达式给其赋值.简单使用如下,它会得到自动生成的Bindging类:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
User user = new User("Test", "User");
binding.setUser(user);
}
现在,xml布局,实体类User,bingding类形成联系,运行程序即可看到user的属性显示在UI上.
当然也可以通过如下方式得到binding类
MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
如果你在ListView或RecycleView的adapter中使用,你可以:
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
//or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
3 Event Handling 事件绑定
严格意义来说,事件绑定也是一种变量绑定.我们可以在xml中直接绑定以下事件:
android:onClick
andriod:onLongClick
android:onTextChanged
…
Method References 方法引用
通常会在java代码中定义一个名为Handler或者Presenter的类,然后set进来,方法签名需和对应listener方法一致。比如:
xml中
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入 First Name"
android:onTextChanged="@{presenter::onTextChanged}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{presenter.onClick}"
android:text="@{employee.firstName}"/>
代码中
@Override
protected void onCreate(Bundle savedInstanceState) {
...
binding.setPresenter(new Presenter());
...
}
public class Presenter {
public void onTextChanged(CharSequence s, int start, int before, int count) {
employee.setFirstName(s.toString());
}
public void onClick(View view) {
Toast.makeText(DemoActivity.this, "点到了", Toast.LENGTH_SHORT).show();
}
}
xml属性中定义onClick或onTextChanged在相应的textview中都有该方法,这样xml定义的事件和Presenter的方法关联起来了.
@{presenter::onTextChanged}
以上是lambda语法,DataBinding支持,意思就是执行presenter的onTextChanged方法.
Listener Bindings 监听器绑定
它可以不遵循默认的方法签名
xml
android:onClick="@{() -> presenter.onClickListenerBinding(employee)}"
代码中
public class Presenter {
public void onClickListenerBinding(Employee employee) {
Toast.makeText(DemoActivity.this, employee.getLastName(),
Toast.LENGTH_SHORT).show();
}
}
xml定义的点击事件会调用onClickListenerBinding方法.
() -> presenter.onClickListenerBinding(employee) 此表达式前面的()代表定义的参数类型,后面的()是要传入的参数值.DataBinding支持忽略所有的参数类型即只写()里面啥都不写或者给所有参数类型命名任意名字但参数的数目要和代码中方法的参数的保持一致,不然会编译时报错.
所以以上表达式也可以写为
(ep) -> presenter.onClickListenerBinding(employee)
4 表达式支持的语法
算术 + - / * %
字符串合并 +
逻辑 && ||
二元 & | ^
一元 + - ! ~
移位 >> >>> <<
比较 == > < >= <=
Instanceof
Grouping ()
文字 - character, String, numeric, null
Cast
方法调用
Field 访问
Array 访问 []
三元 ?:
尚且不支持this, super, new, 以及显示的泛型调用。
空合并运算符,如
android:text=“@{user.displayName ?? user.lastName}”
前者为空取后者,不然取前者.类似三目运算符的简易版本.
我们还可以直接组合字符串,如:
android:text="@{@string/nameFormat(firstName, lastName)}"
<string name="nameFormat">%s, %s</string>
%s代表要替换的字符串
这里提一下,DataBinding不惧怕空指针异常,若表达式结果为null,则根据其结果的值类型显示不同,比如引用类型显示null,int类型显示0,string类型显示空等.
5 Observable
数据绑定后,实体类数据的改变并不会刷新UI的改变,我们希望做到如此,可以使用Observable.
类继承BaseObservable:
private static class User extends BaseObservable {
private String firstName;
private String lastName;
@Bindable
public String getFirstName() {
return this.firstName;
}
@Bindable
public String getLastName() {
return this.lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
}
get方法用Bindable注解,set方法添加notifyPropertyChanged方法.
Observable Fields
如果所有要绑定的都需要创建Observable类,那也太麻烦了。所以Data Binding还提供了一系列Observable,包括 ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, 和ObservableParcelable。我们还能通过ObservableField泛型来申明其他类型,如:
private static class User {
public final ObservableField<String> firstName =
new ObservableField<>();
public final ObservableField<String> lastName =
new ObservableField<>();
public final ObservableInt age = new ObservableInt();
}
Java中如此使用
user.firstName.set("Google");
int age = user.age.get();
我们还可以在此使用集合Observable Collections
比如ObservableArrayMap
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);
<data>
<import type="android.databinding.ObservableMap"/>
<variable name="user" type="ObservableMap<String, Object>"/>
</data>
…
<TextView
android:text='@{user["lastName"]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user["age"])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
比如ObservableArrayList
ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);
在xml中我们可以通过数字下标来进行访问.