前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MVC、MVP、MVVM三剑客

MVC、MVP、MVVM三剑客

作者头像
用户1337002
发布2018-03-09 10:34:54
1.1K0
发布2018-03-09 10:34:54
举报
文章被收录于专栏:猿份到

概述

说到Android MVVM,相信大家都会想到Google 2015年推出的DataBinding框架。然而两者的概念是不一样的,不能混为一谈。MVVM是一种架构模式,而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个工具。

之前看过很多的文章都有简单的介绍MVVM架构如何使用的,但是呢自己总是一知半解的状态,今天通过再次的学习,终于对MVVM有了一个更深刻的理解,现在就来分享下自己的心得。

MVC、MVP、MVVM

首先让我们来了解下Android中常见的开发模式。

MVC

View:XML布局文件。 Model:实体模型(数据的获取、存储、数据状态变化)。 Controller:对应于Activity,处理数据、业务和UI。

从上图可以看出,Android本身的设计还是符合MVC架构的,但是Android中纯粹作为View的XML视图功能太弱,我们大量处理View的逻辑只能写在Activity中,这样Activity就充当了View和Controller两个角色并且耦合度也很高,直接导致Activity中的代码大爆炸。

相信大多数Android开发者都遇到过一个Acitivty数以千行的代码情况吧!所以,因此这个MVC结构最终其实只是一个Model-View(Activity:View&Controller)的结构。

MVP

Model: 依然是实体模型。

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

上面我们说到了mvc中的activity充当了View和Controller的角色,而MVP很好的解决了这个问题,核心理念是通过一个抽象的View接口(不是真正的View层,也就是我们常用的VIewInterface)将Presenter与真正的View层进行解耦。

Persenter持有该View接口,对该接口进行操作,而不是直接操作View层。这样就可以把视图操作和业务逻辑解耦,从而让Activity成为真正的View层。有一定的好处就是团队协作,便于开发。

不过它也有弊端:

该模式有点像分模块分包处理一样,每一个模块中都会存在大量的presenter、view、model、viewInterface这样的包名,当业务量过大时,代码量依旧是庞大臃肿,而且每个模块之间如果有相同的功能或者网络请求的时候,并不能进行代码复用,只能在不同的包中copy一次相同的代码。如果说要更新UI操作的时候需要改动的是V和P层,通过在V层添加接口在P层中实现接口来达到更新UI的效果,在一定程度上还是存在了耦合性的。

MVVM

Model: 实体模型。

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

其实关于MVVM,之前有过错误的理解,一度认为是四层,当然现在肯定不会这样认为了。

从这个图和上面的两个图相比,明显的感觉到了这个图比之前的更为简单更为方便。其实MVVM就是MVP的升级版,MVVM的目标和思想与MVP类似,利用数据绑定(Data Binding)、依赖属性(Dependency Property)、命令(Command)、路由事件(Routed Event)等新特性,打造了一个更加灵活高效的架构。

Google在2015年就提出了要使用这种框架,那我们来看看它的神奇之处。

databinding顾名思义就是数据绑定,通过使用databinding来把数据和UI页面进行关联。

View

View层做的就是和UI相关的工作,我们只在XML、Activity和Fragment写View层的代码,View层不参与业务逻辑,也就是我们在Activity不写业务逻辑和业务数据相关的代码,更新UI通过数据绑定实现,尽量在ViewModel里面做(更新绑定的数据源即可),Activity要做的事就是初始化一些控件(如控件的颜色,添加RecyclerView的分割线),View层可以提供更新UI的接口(但是我们更倾向所有的UI元素都是通过数据来驱动更改UI),View层可以处理事件(但是我们更希望UI事件通过Command来绑定)。 简单地说:View层不做任何业务逻辑、不涉及操作数据、不处理数据,UI和数据严格的分开。

ViewModel

ViewModel只做和业务逻辑和业务数据相关的事,不做任何和UI相关的事情,ViewModel 层不会持有任何控件的引用,更不会在ViewModel中通过UI控件的引用去做更新UI的事情。 ViewModel就是专注于业务的逻辑处理,做的事情也都只是对数据的操作(这些数据绑定在相应的控件上会自动去更改UI)。 与此同时DataBinding框架支持双向绑定,可以通过双向绑定获取View层反馈给ViewModel层的数据,并对这些数据上进行操作。 关于对UI控件事件的处理,我们也希望能把这些事件处理绑定到控件上,并把这些事件的处理统一化,为此我们通过BindingAdapter对一些常用的事件做了封装,Command会把你可能需要的数据带给你,这使得我们在ViewModel层处理事件的时候只需要关心处理数据就行了。 强调:ViewModel 不做和UI相关的事。

Model

model层和mvp、mvc中的model没有什么区别,定义一个实体类进行数据的获取和存储而已 最后:Model只是一个实体类

敲黑板了,敲黑板了。重点来了

MVVM的编译方式和其他模式不同,它是实时编译的,所以我经常遇到一些莫名奇妙的问题。

PS:

1、BR类不存在(BR类生成跟我们所说的R文件是一样的性质),当我第一次使用的时候我方了,正是因为他实时编译的特性让我懵逼了。不过后面发现其实在日志的最后都会告诉你具体的原因了,大部分情况都是xml类中写错了,所以要注意了哦。

2、控件上没有值,控件没有值看你数据源有没有问题或者数据源有没有传递进去

目前遇到的也就是这些问题。

下面聊聊使用心得

1、首先我们在xml中写好相对应的界面和数据绑定关系

2、然后再Activity将页面和数据绑定起来

代码语言:javascript
复制
HomeLoanActBinding binding = DataBindingUtil.setContentView(this, R.layout.home_loan_act);
Intent intent = getIntent();
loanCtrl = new LoanCtrl(binding.apply, intent.getStringExtra(BundleKeys.LOANMONEY), intent.getStringExtra
        (BundleKeys.LOANLIMIT), intent.getStringExtra(BundleKeys.REALMONEY), intent.getStringExtra(BundleKeys.FEE), intent.getStringExtra(BundleKeys
        .CARDNAME), intent.getStringExtra(BundleKeys.CARDNO), intent.getStringExtra(BundleKeys.CARDID));
binding.setViewCtrl(loanCtrl);
代码语言:javascript
复制
HomeLoanActBinding binding = DataBindingUtil.setContentView(this, R.layout.home_loan_act);

通过DataBindingUtil将xml文件和activity进行关联起来,实现页面的绑定。注意

HomeLoanActBinding的生成规则是当前的activity命名加上Binding的形式。如:TestActivity生成的Binding就是TestActivityBinding.

代码语言:javascript
复制
binding.setViewCtrl(loanCtrl);

这个setViewCtrl就是将数据绑定,通过这样的两步我们就将数据和页面进行关联。

上面说到了LoanCtrl,当然他有一个自己的实体类LoanVM,这个就是我们所谓的Model类了,在这个类中我们通过使用databind的一些注解来设置一些属性的值或者是效果。

可以理解为自己写的一个方法,通过bindingAdapter来进行绑定,然后再xml中通过app:xxx(就是@bindingadapter注解的那个值)来进行调用

特别值得一提的就是在set方法中调用notifyPropertyChanged来实现数据的刷新

代码语言:javascript
复制
public void setStepEnable(boolean stepEnable) {
    this.stepEnable = stepEnable;
    notifyPropertyChanged(BR.stepEnable);
}

获取你会问BR.stepEnable怎么来的,这个其实就是VM的属性值。set方法中能做的不仅如此,如果说有一些逻辑的判断也是可以在这个里面进行的处理的

代码语言:javascript
复制
public void setPhone(String phone) {
    this.phone = phone;
    checkPhoneInput();
    notifyPropertyChanged(BR.phone);
}
代码语言:javascript
复制
private void checkPwdInput() {
    if (TextUtil.isEmpty(pwd) || pwd.length() < 6) {
        setEnable(false);
    } else {
        setEnable(true);
    }
}

是不是很强大,之前就算是使用MVP的模式我们都需要在V层将这种逻辑先写出来,做到了真正的解耦。不过弊端就是需要你要熟悉它的用法和了解它的编译,能很好的解决bug。

其他关于MVVM的基本资料就请大家自行查阅资料咯。以上就是我对MVVM的一些心得总结。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-10-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 猿份到 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档