注:主要参考精通 Android Data Binding,官方文档,感谢分享。
一、准备工作
- 要求Android Studio版本是1.5+,使用eclipse的同学暂时还没有办法使用该框架
classpath 'com.android.tools.build:gradle:1.5.0'
- 修改对应模块(Module)的 build.gradle
dataBinding {
enabled true
}
二、MVVM的简单应用
第一步:创建XML布局
创建一个布局xml文件,就像以前一样,我们需要在那个view中使用,就按照固定写法操作。在这个框架下我们的思维要稍稍改变一下了,以前的布局XML只描述了布局,它是相对固定的东西,在Data Binding Library下我们的布局XML就像是一个类,他可以有变量也能进行一定的运算。其实Data Binding Library还真的给你生成了一个类似这样的类(这个类在绑定数据时会用到,命名规则:activity_main.xml—》ActivityMainBinding)。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><!--layout层,不是常见的5种布局;命名空间-->
<data>
<import type="com.xfyb.mvvmtest.User"></import><!--导包,一次导入,下面都可以使用该类。前提是我们已经创建出来了该类-->
<variable
name="user"
type="User"/><!--创建对象-->
</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="@{user.name}"/><!--View中使用变量用@{} 格式来调用-->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="change"
android:text="change"/>
</LinearLayout>
</layout>
第二步:定义数据对象
在上面中我们提到需要创建User的对象,因此我们需要将其创建出来。
public class User {
private String Name;
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
Name = name;
}
private int age;
public User(String name, int age) {
Name = name;
this.age = age;
}
public int getAge() {
return age;
}
public String getName() {
return Name;
}
}
这个类就是一个简单的Bean类,也就是我们在View中需要调用的对象属性。
第三步:绑定数据
public class MainActivity extends AppCompatActivity {
User user;
ActivityMainBinding binding;//自动生成的类ActivityMainBinding其实就是代表了那个布局,里面包括了布局的View,我们声明的变量。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* setContentView(R.layout.activity_main);*/
binding = DataBindingUtil.setContentView(this, R.layout
.activity_main);//原来设置布局的setContentView改成了DataBindingUtil.setContentView
user = new User("XK",18);//创建对象,赋初始值
binding.setUser(user);
}
public void change (View view){
user.setName("KX");
binding.setUser(user);
}
}
基于以上三步,我们就将基于Data Binding 的MVVM的简单编写就完成了,当我们实际运行时,如下界面:
但是当我们点击BUTTON时发现无法更改name的值,无法刷新textView。
解决方案:
1、让实体类继承BaseObservable类
修改后的代码如下所示:
public class User extends BaseObservable {//继承自BaseObservable
private String Name;
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
Name = name;
}
private int age;
public User(String name, int age) {
Name = name;
this.age = age;
}
@Bindable//添加注解
public int getAge() {
return age;
}
@Bindable
public String getName() {
return Name;
}
}
当我们再次点击时,就会修改name属性的值。
至此我们对于MVVM的简单应用就完成了,对于此应用我们主要是注意书写的规范及格式就可以了,特别是对于xml的文件的配置、User类的注解和绑定数据使用时的规范。
总结:
使用基于Data Binding的操作有以下优势:
- 1、不需要在Activity里写很多的findViewById
- 2、在xml中我们只需要通过import导入需要的类的全包名,下面都可以使用。
- 3、引用绑定数据的对象时的格式:以@开始,以{}包裹的形式出现,而内容呢?是user.name。user就是我们上面定义的variable。
三、MVVM的高级应用
1、使用类中方法
- 定义一个静态方法
public static String capitalize(final String word) {
if (word.length() > 1) {
return String.valueOf(word.charAt(0)).toUpperCase() + word.substring(1);
}
return word;
}
- 在 xml 的 data 节点中导入:
<import type="com.xfyb.mvvmtest.MyStringUtils"></import>
- 使用方法与 Java 语法一样:
<TextView
android:text="@{MyStringUtils.capitalize(user.name)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
总结:
- 使用类中的方法,注意方法的参数和返回值,否则无法正常生成ActivityMainBinding类,导致编译失败
使用类中的方法,与常见的java一样,可以是通过静态方法,也可以与简单应用中对于name的引用一样采用“variable”的格式。
2、类型别名
如果我们在 data 节点了导入了两个同名的类怎么办?
<import type="com.example.home.data.User" />
<import type="com.examle.detail.data.User" />
<variable name="user" type="User" />
这样一来出现了两个 User 类,那 user 变量要用哪一个呢?不用担心,import 还有一个 alias 属性。
<import type="com.example.home.data.User" />
<import type="com.examle.detail.data.User" alias="DetailUser" />
<variable name="user" type="DetailUser" />
3、Null Coalescing 运算符
android:text="@{user.displayName ?? user.lastName}"
就等价于
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
4、属性值
通过 @{} 可以直接把 Java 中定义的属性值赋值给 xml 属性。
<TextView
android:text="@{user.lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
5、Observable Binding
要实现 Observable Binding,首先得有一个 implement 了接口 android.databinding.Observable 的类,为了方便,Android 原生提供了已经封装好的一个类 - BaseObservable,并且实现了监听器的注册机制。我们可以直接继承 BaseObservable。
public class User extends BaseObservable {
private String Name;
public void setAge(int age) {
this.age = age;
notifyPropertyChanged(BR.age);
}
public void setName(String name) {
Name = name;
notifyPropertyChanged(BR.name);//通知改变属性
}
private int age;
public User(String name, int age) {
Name = name;
this.age = age;
}
@Bindable
public int getAge() {
return age;
}
@Bindable
public String getName() {
return Name;
}
}
BR 是编译阶段生成的一个类,功能与 R.java 类似,用 @Bindable 标记过 getter 方法会在 BR 中生成一个 entry。
通过代码可以看出,当数据发生变化时还是需要手动发出通知。 通过调用 notifyPropertyChanged(BR.firstName) 可以通知系统 BR.firstName 这个 entry 的数据已经发生变化,需要更新 UI。
6、带 ID 的 View
在使用Data Binding 有效降低了代码的冗余性,甚至完全没有必要再去获取一个 View 实例。我们可以直接在xml中使用id就可以了
<TextView
android:id="@+id/tv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
在代码中我们可以直接通过banding中找到(类似于java中的类和属性)。
binding.tvShow.setText("xxxx");//直接同对象.属性 获取到
运行后的效果: