Data Binding是一个support包,所以我们可以在Android2.1后的任意版本使用,使用前我们要确保项目的Gradle版本不低于1.5.0-alpha。
环境配置
首先下载Data Binding support Libraay,在我们model的build.gradle添加
dataBinging {
enabled = true
}
如果你的工程有依赖的model,那么在依赖model的build.gradle文件中也需要加上上述代码。
同时我们还需要确保Android Studio的版本在1.3以上,才能够支持Data Binding。
Data Binding 布局文件
使用Data Binging框架的布局文件是用layout标签包裹着一个data 元素和一个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>
variable="user"用来表示一个属性,用来在布局文件中使用,类似于java类中定义了一个user对象,类型是com.example.User这个类 在需要引用的地方使用"@{}"标签,例如给TextView赋值为User对象的firstName这个属性,代码如下
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
数据对象
假设我们有一个名字为User的java对象(POJO)
public class User {
public final String firstName;
public final String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
此类型的对象的属性值是不可以改变的,因此我们也可以使用javaBeans对象
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;
}
}
从数据绑定的角度来看,这两个类是等价的。 用于TextView的android:text属性的表达式@ {user.firstName}将访问前一类中的firstName字段和后一类中的getFirstName()方法。
Data Binding
默认情况下,将根据布局文件的名称生成一个Binding类,将其转换为Pascal大小写并在其后面加上“Binding”。 上面的布局文件是main_activity.xml,所以生成类是MainActivityBinding。 这个类保存从布局属性(例如用户变量)到布局视图的所有绑定,并知道如何为绑定表达式分配值。创建绑定的最简单的方法是在java类inflate布局文件时执行:
@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);
}
现在我们运行我们的程序,就可以看到User的信息显示在UI界面上了。
我们也可以通过:
MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
如果我们是在ListView或者是RecycleView的Adapter的布局文件中只要Data Binding,我们可以使用下面的方式进行绑定
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
//或者是
ListItemBinding binding = DataBindingUtils.inflate(layoutInflate, R.layout.item_list, false);
事件处理
Data Binding允许我们在layout文件中编写绑定处理事件(例如OnClick)。事件属性的名称由监听器方法的名称来确定,但也有一些例外,比如View.OnLongClickListener有一个方法是onLongclik,所以这个时间的属性就是android:onLongClick。我们有两种方式来处理时间:
- 1 方法引用
我们在java类中创建事件的监听方法,而后在layout文件中导入该类,并引用其中的方法。
例子如下:public class MyHandlers { public void onClickFriend(View view) { ... }
}
为layout中的TextView绑定OnClick事件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="handlers" type="com.example.Handlers"/>
<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}"
android:onClick="@{handlers::onClickFriend}"/>
</LinearLayout>
</layout>
需要注意的是,我们引用的方法必须和OnClickListener方法的签名一致。
* 2监听器引用
我们可以直接在layout文件使用lambda表达式编写处理逻辑,这种情况下,我们所引用的代码可以是任意业务逻辑代码。
例如:
public class Presenter {
public void onSaveClick(Task task){}
}
我们创建一个Presenter 这个类,有一个onSaveClick方法,用来点击后保存信息。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="task" type="com.android.example.Task" />
<variable name="presenter" type="com.android.example.Presenter" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{() -> presenter.onSaveClick(task)}" />
</LinearLayout>
</layout>
上面的方法中我们没有定义传递的android.view.View参数,我们可以忽略所有的参数,也可以传递所有的参数,
所以我们还可以携程下面这个形式
android:onClick="@{(view) -> presenter.onSaveClick(view, task)}"
那么我们在Presenter中的方法就要定义成如下形式:
public void onSaveClick(View view, Task task){}
我们还可以用lambda表达式来表示多个参数
public class Presenter {
public void onCompletedChanged(Task task, boolean completed){}
}
<CheckBox android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
如果我们的事件有返回值,那么我们定义的放大的返回值需要和事件的返回值一致,例如
android:onLongClick="@{(view) -> presenter.onLongClick(view, task)}"
由于onLongClickListener的返回值是一个布尔值,那么我们定义的方法的返回值也必须是一个布尔值
public class Presenter {
public boolean onLongClick(View view, Task task){}
}
如果因为表达式的结果是null而不能实例化,Data Binding会返回该类型的默认值。例如:引用类型返回null,int类型返回0,布尔类型返回false,等等。
加入我们需要使用三元运算符,当结果为false时,不做任何操作,那么我们可以直接用void来代替。