MVVM的详细讲解

来源:互联网 发布:小型公司网络规划方案 编辑:程序博客网 时间:2024/06/03 16:01

注:主要参考精通 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");//直接同对象.属性  获取到

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

1 0
原创粉丝点击