MVVM的详细讲解

注:主要参考精通 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"/>

总结:

  1. 使用类中的方法,注意方法的参数和返回值,否则无法正常生成ActivityMainBinding类,导致编译失败
  2. 使用类中的方法,与常见的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");//直接同对象.属性  获取到

运行后的效果:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/xk7298/article/details/54880451