1.配置
* 1.首先在build.gradle添加
android {
....
dataBinding {
enabled = true
}
}
* 2.注意
在Activity中使用DataBindingUtil之前,必须先在Manifest中先注册Activity,否则可能找不到包
2.基础
* 1.布局文件Root元素使用Layout
* 2.配置Data节点
!xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">s
<data>
<import type="com.siyan.databinder.entity.Person" />
<variable
name="p"
type="Person" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{p.name}" />
</LinearLayout>
</layout>
```
刚才在 build.gradle 中添加的那个插件 - com.android.databinding会根据xml文件的名称 Generate 一个继承自 ViewDataBinding 的类。
例如,这里 xml 的文件名叫 activity_Main.xml,那么生成的类就是 ActivityMainBinding
3.代码中绑定
ActivityMainBinding 类是自动生成的,所有的 set 方法也是根据 variable name属性生成的。例如,我们在定义了一个name=“p” 那么就会生成对应的set 方法setP(Person person);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
Person person = new Person("haha", "18");
binding.setP(person);
4.数据对象
public class Person {
private String name;
private String age;
public Person(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
}
5.定义 Variable:其中 type 属性就是我们在 Java 文件中定义的 Person 类。
//俩种引用->类的方式
<data>
//此处相当于导向操作,和Java Import是一个性致
<import type="com.siyan.databinder.entity.Person" />
//因为已经导包,type属性等价于类名,name属性等价于类的变量名
<variable
name="p"
type="Person" />
</data>
<data>
//此处没有导包操作,type属性需要类的全类名,name等价于类的变量名
<variable
name="user"
type="com.liangfeizc.databindingsamples.basic.User" />
</data>
//注意:
java.lang.* 包中的类会被自动导入,可以直接使用,例如要定义一个 String 类型的变量
<data>
<variable
name="name"
type="String" />
</data>
6.使用 Variable :@{name.属性名或者方法名} 使用就像Java代码中调用属性或者方法名。注:@{}是必备的格式
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{p.name}" />
7.高级用法
使用类方法
* 静态方法调用
* 1.首先创建Java static方法
```
#!Java
public static String getTime(){
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Date date = new Date();
return format.format(date);
}
```
* 2.data节点导入
```
#!xml
<import type="com.cj.databinding.utils.Utils" />
```
* 3.Xml中使用
@{Utils.getTime()} 使用起来 和Java调用非常的像
```
#!xml
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@{Utils.getTime()}"
android:textSize="12sp" />
```
* 4.调用带参数的方法
android:text="@{Utils.Gcontent(person.age)}"
android:text='@{Utils.Gcontent("haha")}'
android:text='@{Utils.Gcontent(1314)}'
类型重名
如果我们在data节点导入了俩个同名的类型怎么办?
```
#!xml
<data>
//注意结尾处的包名是相同的,如果类名也相同的话,需要使用 alias给重名的类型 起一个别名,在type使用的时候就需要使用alias起的别名
<import type="com.siyan.databinder.entity.Person" />
<import type="com.cj.entity.Person" alias="HahaPerson" />
<variable
name="p"
type="Person" />
<variable
name="hp"
type="HahaPerson" />
</data>
三元运行符
android:text="@{person.displayName ?? person.Name}"
等价
android:text="@{person.displayName != null ? person.displayName : person.Name}"
事件绑定
DataBinding也提供了事件绑定,使用和静态方法差不多:不同点就是参数必须是(View v)对象
注意:com.android.databinding:dataBinder:1.0-rc0 --->是无法使用 事件绑定的
下面我们来看看如何给Button设置点击事件:
```
#!Java
public void getToast(View v){
Toast.makeText(v.getContext(), "绑定事件", Toast.LENGTH_SHORT).show();
}
```
```
#!xml
<data>
<import type="com.cj.databinding.click.BindingClick"/>
</data>
<Button
android:onClick="@{bdclick.showToast}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/click_showToast" />
数据对象
我们学会了通过binding为我们的变量设置数据,但是不知道你有没有发现一个问题,当我们数据改变的时候会怎样?数据是跟随着改变呢?还是原来的数据呢?这里告诉你答案:很不幸,显示的还是原来的数据?那有没有办法让数据源发生变化后显示的数据也随之发生变化?先来想想ListView是怎么做的, ListView的数据是通过Adapter提供的,当数据发生改变时,我们通过notifyDatasetChanged通过UI去改变数据,这里面的原理其实就是内容观察者,庆幸的是DataBinding也支持内容观察者,而且使用起来也相当方便!
BaseObservable
我们可以通过Observable的方式去通知UI数据已经改变了,当然了,官方为我们提供了更加简便的方式BaseObservable,我们的实体类只需要继承该类,稍做几个操作,就能轻松实现数据变化的通知。如何使用呢? 首先我们的实体类要继承BaseObservale类,第二步在Getter上使用注解@Bindable,第三步,在Setter里调用方法notifyPropertyChanged,第四步,完成。就是这么简单,下面我们来实际操作一下。
```
#!Java
public class Person extends BaseObservable{
private String name;
private String age;
public Person(String name, String age) {
this.name = name;
this.age = age;
}
@Bindable
public String getName() {
return name;
}
@Bindable
public String getAge() {
return age;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
public void setAge(String age) {
this.age = age;
notifyPropertyChanged(BR.age);
}
}
观察getName方法,我们使用了@Bindable注解,观察setName,我们调用了notifyPropertyChanged方法,这个方法还需要一个参数,这个参数是BR,BR参数类似于R.java,保存了我们所有变量的引用地址,这里我们使用了name。
public void click(View view) {
mPerson.setName("黑马");
}
```
ObservableFields家族
上面使用BaseObservable已经非常容易了,但是google工程师还不满足,继续给我们封装了一系列的ObservableFields,这里有ObservableField,ObservableBoolean,ObservableByte,ObservableChar,ObservableShort,ObservableInt,ObservableLong,ObservableFloat,ObservableDouble,ObservableParcelable
ObservableFields的使用方法就更加简单了,例如下面代码:
```
#!Java
public class People {
public ObservableField<String> name = new ObservableField<>();
public ObservableInt age = new ObservableInt();
}
```
只有二个ObservableField变量,并且没有getter和setter,因为我们不需要getter和setter。
```
#!xml
<data>
<import type="com.siyan.databinder.entity.Person" />
<data>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{people.name}"/>
#!Java
//那怎么赋值和取值呢?这些ObservableField都会有一对get和set方法,所以使用起来也很方便了
mPeople = new People();
binding.setPeople(mPeople);
mPeople.name.set("people");
mPeople.age.set(19);
```
Observable Collections
既然普通的变量我们有了ObservableFields的分装,那集合呢?当然也有啦,来看着两个:ObservableArrayMap,ObservableArrayList。使用和普通的Map、List基本相同