Android MVC、MVP和MVVP的概念、运用及区别

少年不识愁滋味,爱上层楼。爱上层楼,为赋新词强说愁。

而今识尽愁滋味,欲说还休。欲说还休,却道天凉好个秋。

一首辛弃疾的《丑奴儿·书博山道中壁》送给大家

概述

MVC、MVP和MVVM都是为了解决界面呈现和逻辑代码分离而出现的模式。经典的MVC模式是M-V-X模式的老祖宗,MVP和MVVM都是在MVC的基础上演化而来。本文分为三个部分:

  1. 概述MVC、MVP和MVVM的概念、区别、以及适用场景。
  2. 用Demo演示MVP及MVVM的使用
  3. 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{

    @Override
    public void getUserInfo(final int id, final OnUserInfoListener listener) {
        // 模拟数据
        new Thread(new Runnable() {
            @Override
            public 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() {
            @Override
            public void getUserInfoSuccess(User user) {
                mUserInfoShow.getUserInfoSucceed(user);
                mUserInfoShow.afterLoading();
            }

            @Override
            public 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;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mUserInfoPresenter = new UserInfoPresenter(this, new GetUserInfoImpl());
        mUserInfoPresenter.getUserInfo(666);
    }

    @Override
    public void beforeLoding() {
        Log.i(TAG, "beforeLoding");
    }

    @Override
    public void getUserInfoSucceed(User user) {
        Log.i(TAG, "id:"+user.getId()+" account:"+user.getAccount()+" pwd:"+user.getPwd());
    }

    @Override
    public void getUserInfoFailed(String msg) {
        Log.i(TAG, "msg=" + msg);
    }

    @Override
    public 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" />

        <variable
            name="user"
            type="User" />

    </data>

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

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(user.id)}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.account}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.pwd}" />

    </LinearLayout>

</layout>

public class MainActivity extends Activity {

    @Override
    protected 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

时间: 2024-10-09 05:51:06

Android MVC、MVP和MVVP的概念、运用及区别的相关文章

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

一  MVC模式: M:model,业务逻辑 V:view,对应布局文件 C:Controllor,对应Activity 项目框架: 代码部分: layout文件(适用于MVC和MVP两个Demo): <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" and

Android MVC MVP MVVM (二)

MVP模型 View主要是Activity,Fragment MVP和MVC的差别 1.Model和View不再直接通信,通过中间层Presenter来实现. 2.Activity的功能被简化,不再充当控制器,主要负责View层面的工作. 原文地址:https://www.cnblogs.com/noigel/p/11725064.html

Android App的设计架构:MVC,MVP,MVVM与架构经验谈

来源: Android App的设计架构:MVC,MVP,MVVM与架构经验谈 和MVC框架模式一样,Model模型处理数据代码不变在Android的App开发中,很多人经常会头疼于App的架构如何设计: 我的App需要应用这些设计架构吗? MVC,MVP等架构讲的是什么?区别是什么? 本文就来带你分析一下这几个架构的特性,优缺点,以及App架构设计中应该注意的问题. 1.架构设计的目的 通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.这样做的好处是使得程序在开发的过程中,开发人员

转: GUI应用程序架构的十年变迁:MVC,MVP,MVVM,Unidirectional,Clean

十年前,Martin Fowler撰写了 GUI Architectures 一文,至今被奉为经典.本文所谈的所谓架构二字,核心即是对于对于富客户端的 代码组织/职责划分 .纵览这十年内的架构模式变迁,大概可以分为MV*与Unidirectional两大类,而Clean Architecture则是以严格的层次划分独辟蹊径.从笔者的认知来看,从MVC到MVP的变迁完成了对于View与Model的解耦合,改进了职责分配与可测试性.而从MVP到MVVM,添加了View与ViewModel之间的数据绑

Android MVC模式

Android MVC模式 [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/51172105 前些天看到一篇关于Android MVC模式的技术贴,觉得非常好,所以跟大家分享一下,顺便也说说自己对Android MVC设计模式的见解~~ 算来学习Android开发已有2年的历史了,在这2年的学习当中,基本掌握了Android的基础知识.越到后面的学习越感觉困难,一来是自认为android没啥可学的了(自认为的,其实还有很

[转]MVVM架构~mvc,mvp,mvvm大话开篇

MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示.作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller. 在MVC里,View是可以直接访问

MVC, MVP, MVVM比较以及区别(上)

原文:MVC, MVP, MVVM比较以及区别(上) MVC, MVP和MVVM都是用来解决界面呈现和逻辑代码分离而出现的模式.以前只是对它们有部分的了解,没有深入的研究过,对于一些里面的概念和区别也是一知半解.现在一边查资料,并结合自己的理解,来谈一下对于这三种模式思想的理解,以及它们的区别.欢迎各位高手拍砖. 阅读目录: 一. MVC, MVP, MVVM诞生的需求? 二. 一段典型的耦合代码 三. MVC模式 3.1 主动MVC 3.2 被动MVC 3.3 Web应用中的MVC框架 3.4

MVC/MVP

MVC/MVP MVP http://blog.csdn.net/xijiaohuangcao/article/details/7925641 http://magenic.com/BlogArchive/AnMVPPatternforAndroid http://www.myexception.cn/android/1640365.html Android敏捷开发指南 http://www.apkbus.com/android-72730-1-1.html 实现模式 MVC/MVP

浅析前端开发中的 MVC/MVP/MVVM 模式

MVC,MVP和MVVM都是常见的软件架构设计模式(Architectural Pattern),它通过分离关注点来改进代码的组织方式.不同于设计模式(Design Pattern),只是为了解决一类问题而总结出的抽象方法,一种架构模式往往使用了多种设计模式. 要了解MVC.MVP和MVVM,就要知道它们的相同点和不同点.不同部分是C(Controller).P(Presenter).VM(View-Model),而相同的部分则是MV(Model-View). Model&View 这里有一个可