Android MVVM架构分析

前言

本文俩个任务:

  • 1.对MVVM进行学习
  • 2.总结梳理MVC-MVP-MVVM的演进过程

什么是MVVM

MVP是对MVC的C的演化,MVVM是对MVP的P的演化。而Android领域的MVVM自身也进行了一次演化,即从2015年DataBinding推出开始,由传统的MVVM到2017谷歌推出了AAC标准架构。并在二者迭代的过程中,也出现了基于传统的DataBinding增强的方案(MVVM Light Toolkit使用指南)。

MVVM是一种思想。即UI随数据更改而更改。它独特的地方就在于它的DataBinding特性。但请注意,虽然Google2015专门发布了一个库叫做DataBinding,但是这里说的DataBinding并不是指的某个具体的库,而是指的一种“行为”指的是一类的”将数据Model映射到View”的框架。譬如老的DataBing库,新AAC的LiveData。

View: 对应于Activity和XML,负责View的绘制以及与用户交互。
Model: 实体模型。
ViewModel: 负责完成View与Model间的交互,负责业务逻辑。

特点

数据驱动

在常规的开发模式中,数据变化需要更新UI的时候,需要先获取UI控件的引用,然后再更新UI。获取用户的输入和操作也需要通过UI控件的引用。在MVVM中,这些都是通过数据驱动来自动完成的,数据变化后会自动更新UI,UI的改变也能自动反馈到数据层,数据成为主导因素。这样MVVM层在业务逻辑处理中只要关心数据,不需要直接和UI打交道,在业务处理过程中简单方便很多。

低耦合度

MVVM模式中,数据是独立于UI的。

数据和业务逻辑处于一个独立的ViewModel中,ViewModel只需要关注数据和业务逻辑,不需要和UI或者控件打交道。UI想怎么处理数据都由UI自己决定,ViewModel不涉及任何和UI相关的事,也不持有UI控件的引用。即便是控件改变了(比如:TextView换成EditText),ViewModel也几乎不需要更改任何代码。它非常完美的解耦了View层和ViewModel,解决了上面我们所说的MVP的痛点。

更新UI

在MVVM中,数据发生变化后,我们在工作线程直接修改(在数据是线程安全的情况下)ViewModel的数据即可,不用再考虑要切到主线程更新UI了,这些事情相关框架都帮我们做了。

团队协作

MVVM的分工是非常明显的,由于View和ViewModel之间是松散耦合的:一个是处理业务和数据、一个是专门的UI处理。所以,完全由两个人分工来做,一个做UI(XML和Activity)一个写ViewModel,效率更高。

可复用性

一个ViewModel可以复用到多个View中。同样的一份数据,可以提供给不同的UI去做展示。对于版本迭代中频繁的UI改动,更新或新增一套View即可。如果想在UI上做A/B Testing,那MVVM是你不二选择。

单元测试

有些同学一看到单元测试,可能脑袋都大。是啊,写成一团浆糊的代码怎么可能做单元测试?如果你们以代码太烂无法写单元测试而逃避,那可真是不好的消息了。这时候,你需要MVVM来拯救。

我们前面说过了,ViewModel层做的事是数据处理和业务逻辑,View层中关注的是UI,两者完全没有依赖。不管是UI的单元测试还是业务逻辑的单元测试,都是低耦合的。在MVVM中数据是直接绑定到UI控件上的(部分数据是可以直接反映出UI上的内容),那么我们就可以直接通过修改绑定的数据源来间接做一些Android UI上的测试。

MVVM的俩种方案

传统方式:DataBinding库

在学习MVVM架构思想之前,首先需要明白dataBinding这个工具如何使用。

在懂了如何使用dataBinding的情况下,再来思考架构模式,我的思路是,这个架构既然是由MVP演化而来,那么我们完全可以按照设计Poresenter的方法来设计ViewModel,ok,这是第一步,然后第二步,我们presenter里边持有了View和Model的引用,并根据业务逻辑对二者进行组织,那么,我们的ViewModel也根据这种思路来写,既然是已数据为驱动,编写设计这个架构代码的切入点肯定还是从Model.loadData()进行切入。在拿到数据之后,我们不再需要像VC或VP那样要考虑”这个数据该放在哪个View控件上”这类问题。

M:数据Bean或IModel,和MVP一样
V:Activity和xml布局
VM:Presenter的进化,只是数据会利用dataBinding框架的双向绑定特性对数据进行绑定,最直观的结果就是我们设置数据不再是拿到某个具体的View,而是利用框架生成的Binding文件setXXX(Bean),譬如ActivityMainBinding.setUser(user)

优势总结:

  • View和Model双向绑定,一方的改变都会影响另一方,开发者不用再去手动修改UI的数据。二者互相自动。
  • 不需要findViewById也不需要butterknife,不需要拿到具体的View去设置数据绑定监听器等等,这些都可以用DataBinding完成。是不是很舒服?
  • View和Model的双向绑定是支持生命周期检测的,不会担心页面销毁了还有回调发生,这个由lifeCycle完成。
  • 不会像MVC一样导致Activity中代码量巨大,也不会像MVP一样出现大量的View和Presenter接口。项目结构更加低耦合。

2017新方案,AAC(LiveData)

AAC入门我之前写过一篇文章,要看的同学戳这里

到了这一步,侧重点在于与传统DataBinding框架的纵向对比,而非与MVP,MVC的横向对比。

还是简要说说AAC的特点:
它有个几个成员:LifeCycle,LiveData,Room,ViewModel。其中前三个都是为ViewModel服务的辅助。抛开Room不谈(数据存储),LiveData和LifeCycle都是和LifecycleRegistryOwner,LifecycleObserver相关的,它们包含声明周期与观察者模式俩层含义。使用观察者模式是为了让数据绑定成为可能,它提供了事件传递的属性。

一般来说,我们封装一个MVVM By AAC的架构遵循以下套路:

  • Model

DataBean extends LiveData impl LifecycleObserver,让Model具备被传递的可能以及和生命周期绑定

  • View

是Activity,通过liveData的observe接收ViewModel传过来的事件传递

final MutableLiveData> users = model.getUsers();
MainActivity extends AppCompatActivity implements LifecycleRegistryOwner {

 users.observe(this, new Observer>() {

                    @Override
                    public void onChanged(@Nullable List userLiveData) {
                        Log.e("MainActivity","更新UI");
                    }
                });
}
  • ViewModel

负责加载数据,逻辑编写,以及将Model以观察者事件形式传递给View


public class UserViewModel extends ViewModel{

    private MutableLiveData> users;

    public MutableLiveData> getUsers() {
        if(null == users){
            users = new MutableLiveData();
        }
        loadUsers();
        return users;
    }

    private void loadUsers() {
        // setValue
    }
}
  • 当然,在API26之后我们完全不需要这么复杂,因为它已经将这一套封装到support包内了。

以下例子是纯框架的使用,并没有进行MVVM的封装,只是为了展示,即使我不继承LiveData这些乱七八糟的类就能在API26+上实现这个功能,可以把这个例子当做练习,改造一下。


    package proxy.zj.com.networklivedata.bean;

    /**
     * Created by thinkpad on 2018/2/27.
     */

    public class TestData {

        String content = "";

        public TestData(String content) {
            this.content = content;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }

public class OkGoActivity extends AppCompatActivity {

    private TextView content;

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

        content = findViewById(R.id.content);
        //"https://api.douban.com/v2/movie/top250?start=0&count=10"

        OkGo.init(this.getApplication());

        //***************************************获取数据********************************************
        final OkGoViewModel model = ViewModelProviders.of(this).get(OkGoViewModel.class);
        findViewById(R.id.getdata).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MutableLiveData data = model.getData();
                data.observe(OkGoActivity.this, new Observer() {
                    @Override
                    public void onChanged(@Nullable TestData o) {
                        content.setText(o.getContent());
                    }
                });
            }

        });
        //*******************************************************************************************

    }
}

总结(MVC->MVP->MVVM)

MVC

M:数据Bean和IModel,数据请求一般写在IModel(impl)
V:xml布局文件
C:Activity,直接持有Model引用,在Activity内直接请求数据,然后再绘制UI

Android MVVM架构分析_第1张图片

MVP

Moudel:
Model还是保持MVC的特性,数据Bean和IModel,数据请求一般写在IModel(impl)

View:
Activity,XML,相比MVC,不单单的再将xml布局文件视为View,Activity也不再作为一个Controller而是作为View的一部分而存在,这也是解耦的一个体现,也符合了Android设计Activity这个组件的初衷。

Presenter:
由Controller进化而来,持有View和Modle的引用,根据业务逻辑将二者进行梳理放置

Android MVVM架构分析_第2张图片

另外关于MVP的代码实践我总结了一张脑图,大分辨率的,点击下载

MVVM

Android MVVM架构分析_第3张图片

mvvm对mvp的横向演进,用(单/双向)绑定机制解放了我们拿到数据关注某个具体控件,并隐式的绑定了View层的生命周期,在内存泄漏上有一定优势。
mvvm对自身的纵向演进,由谷歌2015原生的dataBinding框架到谷歌2017 AAC标准框架(LiveData LifeCycle ViewModel) 。

Thanks

https://www.jianshu.com/p/a898ef83f38c
https://www.jianshu.com/p/53925ccb900e
https://www.jianshu.com/p/c0988e7f31fd //Android官方MVVM框架实现组件化之整体结构(强烈推荐)

你可能感兴趣的:(架构)