欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android MVVM架构分析

程序员文章站 2022-07-02 10:02:55
...

前言

本文俩个任务:

  • 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<List<UserLiveData>> users = model.getUsers();
MainActivity extends AppCompatActivity implements LifecycleRegistryOwner {

 users.observe(this, new Observer<List<UserLiveData>>() {

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

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


public class UserViewModel extends ViewModel{

    private MutableLiveData<List<UserLiveData>> users;

    public MutableLiveData<List<UserLiveData>> 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<TestData>() {
                    @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架构分析

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架构分析

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

MVVM

Android MVVM架构分析

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框架实现组件化之整体结构(强烈推荐)