一. 前言

1. 介绍

MVVM全名是Model-View-ViewModel,MVVM可以看作MVP的升级版。

  • Model:模型层,负责处理数据的加载或存储。与MVP中的M一样。
  • View:视图层,负责界面数据的展示,与用户进行交互。与MVP中的V一样。
  • ViewModel:视图模型,负责完成View于Model间的交互,负责业务逻辑-

2. 作用

降低View和控制模块的耦合,减轻了视图的压力。

3. 流程

  • View与ViewModel进行绑定,能够实现双向的交互。ViewModel数据改变时,View会相应变动UI,反之亦然。
  • ViewModel进行业务逻辑处理,通知Model去更新。
  • Model数据更新后,把新数据传递给ViewModel。

二. MVC实例

还是以点击按钮对数字+1为例子,将其改造成MVVM模式。与MVP不同的地方是,ViewModel会跟View进行绑定。这里会用到Android的 Data Binding。关于Data Binding,可以看下这篇文章介绍:Data Binding Library

使用的时候需要到对应模块的build.gradle文件中添加使用代码:

1. Model层

跟MVP的一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class NumModel {
private int num = 0;

public void add(ModelCallback callback){
callback.onSuccess(++num);
}

/**
* 数据回调接口
*/
public interface ModelCallback {
void onSuccess(int num);
void onFailed(int num);
}
}

2. View层

将根布局修改为layout,加入 Data Binding。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data class=".VmActivityBinding">
<variable
name="numVM"
type="swu.xl.mvvmtest.NumViewModel" />
</data>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">

<TextView
android:id="@+id/tv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:layout_marginBottom="10dp"
android:text="@{numVM.num}"
/>

<Button
android:id="@+id/btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击+1"
android:onClick="@{numVM.onClickAdd}"
/>

</LinearLayout>
</layout>

Build一下项目,生成一些需要的类。

在VmActivity中将View与ViewModel进行绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class VmActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);

//DataBindingUtil.setContentView()方法返回一个数据绑定对象,其命名规则由系统自动生成
VmActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

//View和Model绑定在一起
NumViewModel numViewModel = new NumViewModel();
binding.setNumVM(numViewModel);
}
}

3. ViewModel层

ViewModel负责业务逻辑处理,并且数据有更新直接通知View去更改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class NumViewModel extends BaseObservable {
private String num;

private NumModel numModel;

public NumViewModel() {
numModel = new NumModel();
}

//该注解用于双向绑定,需要与 notifyPropertyChanged()方法结合使用
//该注解用于标记实体类中的get方法或“is”开头的方法,且实体类必须继承BaseObservable
//使用@Bindable注解标记的get方法,在编译时,会在BR类中生成对应的字段,然后与notifyPropertyChanged()方法配合使用,当该字段中的数据被修改时,dataBinding会自动刷新对应view的数据
@Bindable
public String getNum() {
return num;
}

public void setNum(String num) {
this.num = num;

//更新UI
notifyPropertyChanged(BR.num);
}

public void onClickAdd(View view){
//点击事件处理,直接交给Model层
numModel.add(new NumModel.ModelCallback() {
@Override
public void onSuccess(int num) {
setNum(num+"");
}

@Override
public void onFailed(int num) {
setNum("");
}
});
}
}

4. 运行结果

5. 源码

MVVMTest

三. MVP和MVVM的区别

ViewModel与View绑定后,ViewModel与View其中一方的数据更新都能立即通知到对方;Presenter需要通过接口去通知View进行更新。

四. MVC的优缺点

1. 优点

  • 相比于MVP,Presente与View存在耦合。ViewModel与View的耦合则更低,ViewModel只负责处理和提供数据,UI的改变,比如TextView 替换 EditText,ViewModel 几乎不需要更改任何代码,只需专注于数据处理就可以了。

  • View Model里面只包含数据和业务逻辑,没有UI的东西,方便单元测试。

2. 缺点

数据绑定使得程序较难调试,界面出现异常时,有可能是 View 的代码有问题,也可能是 Model 的代码有问题。由于数据绑定使得数据能够快速传递到其他为止,因此要定位出异常就比较有难度了。

参考文章

Android框架模式——MVVM

DataBinding详细的使用方法及工作中常遇到的问题(一)

DataBinding 使用介绍

Android基础——框架模式MVVM之DataBinding的实践

DataBinding使用教程(三):各个注解详解