Data Binding
是Android
待发布的支持库,它能够将逻辑和代码关联起来,避免开发者书写大量的胶合代码,也是实现MVVM架构的必要技术。android
此前,布局文件XML被认为是相对静态的,每每须要在Java代码中处理与其有关的逻辑;数据绑定技术(Data Binding
)改造了布局文件使其可以导入Java类,定义和使用变量,具有像Java代码同样的灵活性,从而使得XML文件变的更加动态化,支持更强大的功能。架构
在项目顶层的gradle
中添加依赖app
dependencies { classpath "com.android.tools.build:gradle:1.2.3" classpath "com.android.databinding:dataBinder:1.0-rc0" }
在具体模块gradle
配置文件中启用该插件函数
apply plugin: 'com.android.databinding'
给出一个Model
层的User
类布局
public class User { public final String firstName; public final String lastName; //get&set .... }
在View
层使用一个TextView
专门负责显示User
的两个名字。
在通常的实现中,TextView
和User
类每每都在Activity
中实例化,并实现交互逻辑。在MVP架构中,专门设立主导器P负责交互逻辑,并将User
类的实例化从Activity
中移出。
使用数据绑定能够在TextView
的布局文件中就用User
对象指定其显示的内容。这个布局文件databinding_layout.xml
以下gradle
//1.根标签为 layout <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> //2.data标签订义所使用数据域对象 <data> //3.variable标签根据Java类创建变量 <variable name="user" //声明变量名称 type="com.example.migratingtest.User" //指定变量类型 /> </data> //4.静态布局 <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_margin="20dp" android:padding="20dp" android:background="#55ffff00" //5.用@{user.firstName}格式使用定义的类对象user android:text="@{user.firstName}+@{user.getLastName()}" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> </layout>
布局文件中定义了数据层user
和视图层textview
的对应关系,但要传入的对象user
还须要在Java代码中生成;同时这个布局文件将按名称生成一个DatabindingLayoutBinding
类,位于app\build\intermediates\classes\debug\<包名>\databinding
目录下,须要在Java代码中做为布局载入;然后将两者绑定起来。ui
//1.载入新布局类 DatabindingLayoutBinding binding = DataBindingUtil.setContentView(this, R.layout.databinding_layout); //2.产生User对象 User user = new User("liu", "xiangtian"); //3.绑定布局和具体对象 binding.setUser(user);
布局文件中data
能够像Java代码同样导入类,并直接使用其类静态变量/方法,使用variable
标签声明和创建对象;this
类和对象的域/方法都可以在布局文件中使用,也支持相关运算,如上例中的字符链接符+
。spa
上述仅是数据绑定的基本功能,若是User
对象一被改变,布局界面就自动更新,数据绑定才显得名副其实。其实现很容易让人联想到观察者模式,User
对象继承Observable
做为被观察者,但问题是这种实现更新须要主动使用notify
函数来通知观察者们;为此,android
使用BaseObservable
类和Bindable
注解实现自动通知。插件
要改的仅仅是User
类。
//1.继承BaseObservable类成为被观察者 public class User extends BaseObservable{ public String firstName; //2.给get方法Bindable注解 @Bindable public String getFirstName() { return firstName; } //3.给set方法添加`notify`方法 public void setLastName(String lastName) { this.lastName = lastName; notifyPropertyChanged(BR.lastName); } }
BR
亦是编译时生成类,一样位于app\build\intermediates\classes\debug\<包名>\
目录下,其内容是:
public class BR { public static final int _all = 0; public static final int firstName = 1; public static final int lastName = 2; public static final int user = 3; }
此后当使用user.setFirstName("li")
更改数据后,布局中将相应变化。
由BR
代码可知,User
类中全部域均被编入被观察者列表中,这有时并不合理。为了灵活起见,可使用ObservableFields
单独对某个引用域进行转换,使用ObservableInt
等对基本类型进行转换。
依然改User
类
public class User { public ObservableField<String> firstName = new ObservableField<>(); public ObservableField<String> lastName = new ObservableField<>(); }
在Java代码中初始化User
User user = new User(); //ObservableField是一个包装类,提供get/set方法处理包装的内容对象 user.firstName.set("liu"); user.lastName.set("xiangtian");
布局文件仍然使用
@{user.firstName}
便可,不须要使用@{user.firstName.get}
生成的新布局文件是一个表明绑定关系的类DatabindingLayoutBinding
,这个类继承自ViewDataBinding
,其中包含全部在布局中声明了的类对象 和 参与绑定的所有View
,并提供了相应了set/get
方法以及解除全部绑定的unbind
方法。如示例中
// views private final android.widget.LinearLayout mboundView0; private final android.widget.TextView mboundView1; // variables private com.example.migratingtest.User mUser;