Android MVC、MVP和MVVP的概念、运用及区别
少年不识愁滋味,爱上层楼。爱上层楼,为赋新词强说愁。
而今识尽愁滋味,欲说还休。欲说还休,却道天凉好个秋。
一首辛弃疾的《丑奴儿·书博山道中壁》送给大家
概述
MVC、MVP和MVVM都是为了解决界面呈现和逻辑代码分离而出现的模式。经典的MVC模式是M-V-X模式的老祖宗,MVP和MVVM都是在MVC的基础上演化而来。本文分为三个部分:
- 概述MVC、MVP和MVVM的概念、区别、以及适用场景。
- 用Demo演示MVP及MVVM的使用
- Demo源码下载
概述MVC、MVP和MVVM的概念、区别、以及适用场景。
简述MVC
- M-Model : 业务逻辑和实体模型(biz/bean)
- V-View : 布局文件(XML)
- C-Controllor : 控制器(Activity)
MVC虽然将界面呈现和逻辑代码分离了,但是在实际的Android开发中并没有完全起到想要的作用。View对应的XML文件实际能做的事情很少,很多界面显示由Controllor对应的Activity给做了,这样使得Activity变成了一个类似View和Controllor之间的一个东西。如果是小型项目,MVC是没任何问题的。因为项目比较小嘛,开发周期比较短,Controllor臃肿点也可以理解。假设项目越来越大,尤其是再加上比较复杂的逻辑,这时候一个Activity几千行代码就比较蛋疼了,再加点迷之缩进,那酸爽~~啧啧。所以MVC比较适用于快速开发的小型项目。
简述MVP
- M-Model : 业务逻辑和实体模型(biz/bean)
- V-View : 布局文件(XML)和Activity
- P-Presenter : 完成View和Model的交互
尽管MVC设计的非常nice,但代码臃肿的问题仍然没有得到很好的解决,这个时候MVP就要登场了。可以看到MVP相对于MVC改动是非常大的。Activity直接当做View使用,代替MVC中C的是P-Presenter。对比MVC和MVP的模型图可以发现变化最大的是View和Model不在直接通信,所有交互的工作都通过Presenter来解决。既然两者都通过Presenter来通信,为了复用和可拓展性,MVP模式基于接口设计也就很好理解了。两者都通过Presenter来通信,好很多的好处,例如提高代码复用性啦、增加可拓展性啦、降低耦合度啦、代码逻辑更加清晰啦。但是、本来两个能直接通信的东西现在要通过第三方来通信,那势必会增加很多类。没错,MVP模式虽然很好,但是增加了很多的接口和实现类。代码逻辑虽然清晰,但是代码量要庞大一些。当刚接手一个烂尾的MVP模式,如果事先没了解过MVP,会不会一脸的懵逼。所以MVP比较适用于中小型的项目,大型项目慎用。
简述MVVM
- M-Model : 实体模型(biz/bean)
- V-View : 布局文件(XML)
- VM-ViewModel : binder所在之处,对外暴露出公共属性,View和Model的绑定器
有的读者该说了,你作用这不是和MVC一样嘛!是的,对应的文件看起来确实是一样的,但是作用不同。MVVM和MVP一样,View和Model不允许直接交互。只能通过ViewModel。MVVM神奇的地方在于通过ViewModel隔离了UI层和业务逻辑层,降低程序的耦合度。而且,布局文件里可以进行视图逻辑!并且Model发生变化,View也随着发生变化。布局文件里居然还能写逻辑,斯国一!
Demo演示MVP及MVVM的使用
MVP的代码示例
工程大纲如下:
预览大纲可以发现只有一个Bean:User。业务逻辑只有一个GetUserInfo。先放下View层和Presenter层。我们来看下最简单的Bean层和Biz层(业务逻辑)。
public class User {private int id;private String account;private String pwd;getter()/setter()...
}public interface IGetUserInfo {void getUserInfo(int id, OnUserInfoListener listener);
}public class GetUserInfoImpl implements IGetUserInfo{@Overridepublic void getUserInfo(final int id, final OnUserInfoListener listener) {// 模拟数据new Thread(new Runnable() {@Overridepublic void run() {if (id == 666){User user = new User();user.setId(666);user.setAccount("一口仨馍");user.setPwd("走在勇往直前的路上");listener.getUserInfoSuccess(user);}else{String msg = "损色!获取数据失败啦";listener.getUserInfoFailure(msg);}}}).start();}
}public interface OnUserInfoListener {void getUserInfoSuccess(User user);void getUserInfoFailure(String msg);
}
为了观赏性,省略了部分代码,如有需要可以在第三部分下载源码。这里我们定义了两个接口和实现类。MVP模式的接口之多由此可见一斑。下面一一解释各个类的作用
- User:Bean也可以叫做POJO,纯净的类。
- IGetUserInfo:获取用户信息的接口
- GetUserInfoImpl:获取用户信息的实现类
- OnUserInfoListener:获取用户信息的监听接口
这里我们主要解析下GetUserInfoImpl这个类,GetUserInfoImpl是接口IGetUserInfo的具体实现类。复写了IGetUserInfo#getUserInfo()方法。在GetUserInfoImpl的getUserInfo()方法中,模拟后台请求数据。如果成功请求到User信息,则调用接口OnUserInfoListener#getUserInfoSuccess(User user)
方法。否则调用OnUserInfoListener#getUserInfoFailure(String msg)
方法。
Bean和Biz层的业务逻辑都有了,下面该通知View显示数据。由于View个Model在Presenter中使用接口通信,所以先定义一个用于显示数据的接口。然后在要获取数据的Activity中实现此接口,并复写其中所有的抽象方法。
public interface IUserInfoShow {void beforeLoding();void getUserInfoSucceed(User user);void getUserInfoFailed(String msg);void afterLoading();
}// MainActivity extends Activity implements IUserInfoShow
View层的接口定义完成之后,就剩最后的大Boss-Presenter登场了!
package com.dyk.mvp.presenter; import com.dyk.mvp.bean.User;
import com.dyk.mvp.biz.IGetUserInfo;
import com.dyk.mvp.biz.OnUserInfoListener;
import com.dyk.mvp.view.IUserInfoShow;/*** Created by dyk on 2016/4/14.*/
public class UserInfoPresenter {private IGetUserInfo mIGetUserInfo;private IUserInfoShow mUserInfoShow;public UserInfoPresenter(IUserInfoShow mUserInfoShow, IGetUserInfo mIGetUserInfo) {this.mUserInfoShow = mUserInfoShow;this.mIGetUserInfo = mIGetUserInfo;}public void getUserInfo(int id){mUserInfoShow.beforeLoding();mIGetUserInfo.getUserInfo(id, new OnUserInfoListener() {@Overridepublic void getUserInfoSuccess(User user) {mUserInfoShow.getUserInfoSucceed(user);mUserInfoShow.afterLoading();}@Overridepublic void getUserInfoFailure(String msg) {mUserInfoShow.getUserInfoFailed(msg);mUserInfoShow.afterLoading();}});}
}
在关键的Presenter中,我们定义了一个两个参数的构造方法和一个getUserInfo()方法。
在构造方法中,传进来的两个参数分别是:IUserInfoShow、IGetUserInfo。前者是View层的顶级接口,后者是M层的顶级接口。并且赋给属性mUserInfoShow、mIGetUserInfo。看来今天所有的工作全看他们俩的了!
在getUserInfo()方法中,传进来的参数时id,这个id就是用户的id。在方法的开始调用mUserInfoShow.beforeLoding()
,这意味着我们可以在实现了IUserInfoShow类的beforeLoding()方法中做一些预处理,比如展示Loading动画等等,紧接着调用了mIGetUserInfo.getUserInfo()
,并且new了一个OnUserInfoListener的匿名内部类。也就是我们获取用户信息的监听。接下来就很简单了,如果成功则调用mUserInfoShow.getUserInfoSucceed(user);
和mUserInfoShow.afterLoading();
失败的话调用mUserInfoShow.getUserInfoFailed(msg);
和mUserInfoShow.afterLoading();
。一个简单的Presenter就完成了,剩余的就看IUserInfoShow的实现类
package com.dyk.mvp;import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import com.dyk.mvp.bean.User;
import com.dyk.mvp.biz.GetUserInfoImpl;
import com.dyk.mvp.presenter.UserInfoPresenter;
import com.dyk.mvp.view.IUserInfoShow;public class MainActivity extends Activity implements IUserInfoShow {private static final String TAG = "MVP";private UserInfoPresenter mUserInfoPresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mUserInfoPresenter = new UserInfoPresenter(this, new GetUserInfoImpl());mUserInfoPresenter.getUserInfo(666);}@Overridepublic void beforeLoding() {Log.i(TAG, "beforeLoding");}@Overridepublic void getUserInfoSucceed(User user) {Log.i(TAG, "id:"+user.getId()+" account:"+user.getAccount()+" pwd:"+user.getPwd());}@Overridepublic void getUserInfoFailed(String msg) {Log.i(TAG, "msg=" + msg);}@Overridepublic void afterLoading() {Log.i(TAG, "afterLoading");}
}
在MainActivity#OnCreate()里,首先实例化一个UserInfoPresenter对象,并将GetUserInfoImpl作为第二个参数传入。然后只需执行一行代码mUserInfoPresenter.getUserInfo(666);
即可。Activity的代码是不是看起来简洁的多。Log信息如下:
MVVM代码示例
工程大纲如下:
WTF!居然只有Activity、Bean以及一个activity_main.xml?是的,MVVP就是这么简洁。可是简洁不意味着简单。Google去年I/O大会发布了一款MVVP的框架,data binding。今天以此框架为例。
在Module的build.gradle中添加
dataBinding {enabled true
}
代码很少,直接贴上来了。后面会仔细解释。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><import type="com.dyk.mvvp.bean.User" /><variablename="user"type="User" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="@{String.valueOf(user.id)}" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="@{user.account}" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="@{user.pwd}" /></LinearLayout></layout>public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);binding.setUser(new User(666,"一口仨馍", "走在勇往直前的路上"));}
}
Run一下试试看。区区几行代码就搞定了User信息的绑定与展示首先看布局文件。最外层为layout。其次定义了data元素,里面有个变量(variable)名称为user,类型为com.dyk.mvvp.bean.User
中的User,也就是我们的Bean。然后在TextView.setText()
中直接使用user.account属性就可以获取到user的属性,无论是否私有。Java基本类型不用使用import导包,另外还支持Java语法。可以看到id属性使用了String.value()
方法转换为String。然后再MainActivity中没有直接setContentView()
而是调用DataBindingUtil.setContentView(this, R.layout.activity_main);
返回的是个继承ViewDataBinding
的泛型。这里是ActivityMainBinding
,注意下,这个返回泛型名称是有规则的:布局文件去掉下划线,后面第一个字母大写,再加上Binding。例如这里的布局文件为activity_main
,对应的泛型为:ActivityMainBinding
,这里只是一个示例。感兴趣的同学可以去仔细研究data binding框架。
源码下载 : http://download.csdn.net/detail/qq_17250009/9492043
参考:
http://blog.csdn.net/loongggdroid/article/details/50592777
http://blog.csdn.net/lmj623565791/article/details/46596109
http://rocko.xyz/2015/02/06/Android%E4%B8%AD%E7%9A%84MVP/
http://rocko.xyz/2015/11/07/MVVM_Android-CleanArchitecture/
http://blog.csdn.net/johnny901114/article/details/50706329
http://blog.csdn.net/qibin0506/article/details/47393725
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/1110/3669.html
Android MVC、MVP和MVVP的概念、运用及区别相关推荐
- android mvc mvp 区别,谈谈Android框架 MVC、MVP、MVVM的区别
今天写写Android的MVC.MVP.MVVP三个框架的对比,并加深自己对这三个框架的理解. 548b9bea8dc18.gif 一 . MVC:Model-View-Controller MVC全 ...
- android MVC,MVP,MVVM
1.MVC思想 无论在任何情况下,软件设计都要符合高内聚,低耦合的思想.如果背离这一原则,代码将很难进入维护. MVC出现与上世纪70年代,在三十多年的工程实践中,MVC充分证明了它的成功.在软件开发 ...
- android MVC,MVP,MVVM概论
1.MVC思想 无论在任何情况下,软件设计都要符合高内聚,低耦合的思想.如果背离这一原则,代码将很难进入维护. MVC出现与上世纪70年代,在三十多年的工程实践中,MVC充分证明了它的成功.在软件开发 ...
- Android MVC,MVP,MVVM模式入门——重构登陆注册功能
一 MVC模式: M:model,业务逻辑 V:view,对应布局文件 C:Controllor,对应Activity 项目框架: 代码部分: layout文件(适用于MVC和MVP两个Demo): ...
- android mvc mvp 简书,浅析 MVP,MVC,MVVM模式(Android)
前言 当我们接手一个项目的时候,经常会发现一个activity或fragment动辄上千行甚至上万行代码,这给阅读带来很大的困扰,如果想读懂代码,需要花费很多时间跟精力.引起这个问题的原因想必大家都了 ...
- Android MVC ,MVP,MVVM 常见架构浅谈
简述:其实任何架构的目的都是:提高开发效率,降低维护成本: MVC: Model: 负责处理数据逻辑,一般包括操作数据库,耗时网络操作等组成: View:负责处理视图: 一般是xml布局: Contr ...
- Android App的设计架构:MVC,MVP,MVVM与架构经验谈
本文转载自https://www.tianmaying.com/tutorial/AndroidMVC,原文作者周鸿博. 和MVC框架模式一样,Model模型处理数据代码不变在Android的App开 ...
- Android中常见的MVC/MVP/MVVM模式
Android中常见的MVC/MVP/MVVM模式 经典MVC 在1979年,经典MVC模式被提出. 在当时,人们一直试图将纯粹描述思维中的对象与跟计算机环境打交道的代码隔离开来,而Trygve Re ...
- Android 系统(77)---MVC,MVP,MVVM的区别
MVC,MVP,MVVM的区别 一.MVC 软件可以分为三部分 1.Model:模型层,负责处理数据的加载或者存储 2. View:视图层,负责界面数据的展示,与用户进行交互 3.Controll ...
最新文章
- yum源及yum仓库服务搭建讲解
- (转)面向对象的 JavaScript 编程:dojo.declare 详解
- linux/windows nginx安装
- RabbitMQ启动参数具体含义
- 查看磁盘uuid命令_Win10推出新的命令行工具,可以查看磁盘空间使用情况
- 深入理解strncpy这个函数
- python matplotlab.pyplot.axis()函数的用法
- phpstudy编写php扩展,PHP_探讨:如何编写PHP扩展,用C/C++扩展PHP的优缺点:优点 - phpStudy...
- DLP Lightcrafter™ 4500 EVM常见问题答疑
- Ajax 入门Demo
- 为什么要做用户行为分析?
- MISC互相伤害!!!
- 用 shader effect 实现雨滴落水效果!Cocos Creator 3D !
- HTML+CSS静态网页制作:电影介绍(11页) HTML+CSS+JavaScript
- 【降维打击】希尔伯特曲线
- linux oracle开启监听服务器,linux服务器启动oracle监听端口
- Heap size 80869K exceeds notification threshold (51200K)
- 推荐系统从入门到 Spark 案例实践
- 如何把计算机软件卸载干净
- matlab怎么画probit,matlab对于probit模型怎么求统计值(赠probit程序)