• 概念解释

    • MVP是Model(数据) View(界面) Presenter(表现层)的缩写,它是MVC架构的变种,强调Model和View的最大化解耦和单一职责原则
    • Model:负责数据的来源和封装,比如网络请求类,数据库操作类以及java bean,如果有必要则提供接口暴露自己处理数据的状态和进度。
    • View:负责UI相关,如布局UI的初始化,各种listener的设置。在Android中,我们通常写的Activity和Fragment就是属于View层;在web开发中,html则是View层。
    • Controller:业务逻辑控制器,主要负责当获取到数据后对数据进行逻辑处理,然后将数据绑定到View上;比如:请求一个url,从网络获取到数据,进行解析javabean,然后各种set数据。对于控制器的概念大家很好理解,因为我们每天都在这样做,在Activity中请求数据然后更新UI。但是结合View的概念来看,很显然Activity和Fragment不但承担了View的任务,还负责完成的Controller的功能,随着业务功能的增多,Activity的代码越来越难以阅读和维护,这就是在Android中使用MVC的弊端,为了解决MVC模式下View层的臃肿,MVP模式应运而生。
    • Presenter:专门从C独立出来的业务逻辑层,主要负责处理原先View层的业务逻辑,解决了Activity的臃肿问题,让Activity只负责处理UI,职责更加明确;并且将View层的业务逻辑抽取到P层之后,View层与Model层也实现了解耦;便于后期代码的扩展和维护,并且业务逻辑层独立后代码还得到很大的重用性
    • 总结:MVC模式下,V和C纠缠不清,并且View和Model相互关联,而MVP模式下Model和VIew解耦,便于单元测试,项目维护,代码重用
  • 先看看一个登录界面的业务逻辑和UI更新全部写在Activity的代码:

    public class LoginActivity extends ActionBarActivity implements OnClickListener{
    EditText etUsername,etPassword;
    Button btn_login;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    etUsername = (EditText) findViewById(R.id.et_username);
    etPassword = (EditText) findViewById(R.id.et_password);
    btn_login = (Button) findViewById(R.id.btn_login); //设置点击事件
    btn_login.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
    switch (v.getId()) {
    case R.id.btn_login:
    String username = etUsername.getText().toString();
    String password = etPassword.getText().toString(); if(checkInput(username,password)){
    //提交登录
    //执行登录请求
    execLogin(username, password);
    } break;
    }
    }
    //执行登录请求
    public void execLogin(String username,String password){
    //执行登录请求的伪代码
    HttpHelper helper = new HttpHelper();
    helper.execRequest("http://www.baidu.com", new HttpCallback() {
    @Override
    public void onSuccess() {
    //提示登录成功
    showLoginSuccess(LoginActivity.this); //保存登录相关数据,如登录的标记,用户的唯一标识
    saveLoginData();
    }
    @Override
    public void onFail() {
    //关闭登录对话框
    hideLoginDialog(LoginActivity.this);
    //提示登录失败
    showLoginFail(LoginActivity.this);
    }
    });
    }
    //保存登录数据
    public void saveLoginData(){
    //保存登录相关的数据,代码略过...
    }
    //提示登录成功
    public void showLoginFail(Context context){
    Toast.makeText(context, "登录失败", 0).show();
    }
    //提示登录失败
    public void showLoginSuccess(Context context){
    Toast.makeText(context, "登录成功", 0).show();
    }
    //检查输入的合法性
    private boolean checkInput(String username, String password) {
    boolean result = true;
    //1.检查为空
    if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)){
    Toast.makeText(this, "用户名或者密码不能为空!", 0).show();
    result = false;
    }
    //2.检查长度
    if(username.length()!=11){
    Toast.makeText(this, "用户名长度不正确!", 0).show();
    result = false;
    }
    if(password.length()<5){
    Toast.makeText(this, "密码长度不能小于5位!", 0).show();
    result = false;
    }
    return result;
    }
    }

    现在抽取出LoginPresenter类,如下:

    /**
    * 业务逻辑封装层
    * @author lxj
    *
    */
    public class LoginPresenter {
    private ILoginView loginView; /**
    * 生命周期相关方法
    */
    public void onDestory(){
    //do something to release and avoid memory leak;
    }
    public void onStart(){
    //do something when onStart
    }
    public void onStop(){
    //do something when onStop
    }
    public void onResume(){
    //do something when onResume
    }
    public void onPause(){
    //do something when onPause
    } public LoginPresenter(ILoginView loginView){
    this.loginView = loginView;
    }
    //登录的方法
    public void login(String username, String password) {
    if(!checkInput(username, password)){
    return;
    }
    // 执行登录请求的伪代码
    HttpHelper helper = new HttpHelper();
    helper.execRequest("http://www.baidu.com", new HttpCallback() {
    @Override
    public void onSuccess() {
    // 需要UI展示,暴露接口
    loginView.showLoginSuccess();
    // 保存登录相关数据,如登录的标记,用户的唯一标识
    saveLoginData();
    }
    @Override
    public void onFail() {
    // 需要UI展示,暴露接口
    loginView.showLoginFail();
    }
    });
    }
    private void saveLoginData() {
    //do something
    }
    // 检查输入的合法性
    private boolean checkInput(String username, String password) {
    boolean result = true;
    // 1.检查为空
    if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
    loginView.showInputNoNull();
    result = false;
    }
    // 2.检查长度
    if (username.length() != 11) {
    loginView.showUsernameLengthError();
    result = false;
    }
    return result;
    }
    }

    View和P解耦接口如下ILoginView:

    public interface ILoginView {
    void showLoginSuccess();
    void showLoginFail();
    void showInputNoNull();
    void showUsernameLengthError();
    }

    最后的View层编写如下:

    public class LoginActivity extends Activity implements OnClickListener,ILoginView{
    EditText etUsername,etPassword;
    Button btn_login;
    private LoginPresenter loginPresenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    etUsername = (EditText) findViewById(R.id.et_username);
    etPassword = (EditText) findViewById(R.id.et_password);
    btn_login = (Button) findViewById(R.id.btn_login);
    //设置点击事件
    btn_login.setOnClickListener(this);
    //与loginPresenter交互
    loginPresenter = new LoginPresenter(this); }
    @Override
    public void onClick(View v) {
    switch (v.getId()) {
    case R.id.btn_login:
    String username = etUsername.getText().toString();
    String password = etPassword.getText().toString();
    loginPresenter.login(username,password);
    break;
    }
    }
    public void showLoginSuccess(){
    Toast.makeText(this, "登录成功", 0).show();
    }
    public void showLoginFail(){
    Toast.makeText(this, "登录失败", 0).show();
    }
    public void showInputNoNull(){
    Toast.makeText(this, "用户名和密码不能为空!", 0).show();
    }
    public void showUsernameLengthError(){
    Toast.makeText(this, "用户名长度不正确!", 0).show();
    }
    public void hideLoginDialog(){
    if(progressDialog!=null){
    progressDialog.dismiss();
    }
    } @Override
    protected void onResume() {
    super.onResume();
    loginPresenter.onResume();
    }
    @Override
    protected void onStart() {
    super.onStart();
    loginPresenter.onStart();
    }
    @Override
    protected void onStop() {
    super.onStop();
    loginPresenter.onStop();
    } @Override
    protected void onPause() {
    super.onPause();
    loginPresenter.onPause();
    } @Override
    protected void onDestroy() {
    super.onDestroy();
    loginPresenter.onDestory();
    }
    }

    总结:MVP只是给我们提出了分层解耦的思想,并没有一个固定的实现。Google虽然出了官方的MVP实现示例,但是并没有太多人去跟随,很多公司在对Presenter层都有自己的理解,此处的案例相对来说比较规范,对MVP三层都有清晰的解耦和实现,在茫茫开源项目中,算是比较好的容易理解的上手项目了。

MVP架构模式的更多相关文章

  1. 用户登录(Material Design + Data-Binding + MVP架构模式)实现

    转载请注明出处: http://www.cnblogs.com/cnwutianhao/p/6772759.html MVP架构模式 大家都不陌生,Google 也给出过相应的参考 Sample, 但 ...

  2. iOS - MVP 架构模式

    1.MVP 从字面意思来理解,MVP 即 Modal View Presenter(模型 视图 协调器),MVP 实现了 Cocoa 的 MVC 的愿景.MVP 的协调器 Presenter 并没有对 ...

  3. 设计模式笔记之一:MVP架构模式入门(转)

    写在前面:昨天晚上,公司请来专家讲解了下MVP,并要求今后各自负责的模块都要慢慢的转到MVP模式上来.以前由于能力有限,没有认真关注过设计模式.框架什么的,昨晚突然兴趣大发,故这两天空闲时间一直在学习 ...

  4. 死磕安卓前序:MVP架构探究之旅—基础篇

    前言 了解相关更多技术,可参考<我就死磕安卓了,怎么了?>,接下来谈一谈我们来学习一下MVP的基本认识. 大家对MVC的架构模式再熟悉不过.今天我们就学习一下MVP架构模式. MVC和MV ...

  5. Android MVP开发模式及Retrofit + RxJava封装

    代码已上传到Github,因为接口都是模拟无法进行测试,明白大概的逻辑就行了! 欢迎浏览我的博客--https://pushy.site 1. MVP模式 1.1 介绍 如果熟悉MVP模式架构的话,对 ...

  6. iOS 架构模式--解密 MVC,MVP,MVVM以及VIPER架构

    本文由CocoaChina译者lynulzy(社区ID)翻译 作者:Bohdan Orlov 原文:iOS Architecture Patterns 在 iOS 中使用 MVC 架构感觉很奇怪? 迁 ...

  7. 浅谈MVC、MVP、MVVM架构模式的区别和联系

    MVC.MVP.MVVM这些模式是为了解决开发过程中的实际问题而提出来的,目前作为主流的几种架构模式而被广泛使用. 一.MVC(Model-View-Controller) MVC是比较直观的架构模式 ...

  8. MVC、MVCS、MVVM、MVP、VIPER等这么多架构模式哪一个好呢?

    在项目开启阶段,其中一个很重要的环节就是选架构. 那么面对目前已知的这么多架构模式我们该怎么选择呢?这确实是个很让人头疼的问题!   下面我就在这里梳理一下目前常见的一些架构模式. 先逐个对它们的分析 ...

  9. 浅谈MVP架构及开发模式

    Model-View-Presenter(MVP)概述    MVC模式已经出现了几十年了,在GUI领域已经得到了广泛的应用,由于微软ASP.NET MVC Framework的出现,致使MVC一度成 ...

随机推荐

  1. jni——如何转换有符号与无符号数

    java数据结构默认均为有符号数,而通过jni转换到c/c++层,却不一定是有符号数. 如若在java中存储的即为无符号数,则在jni中可将jbyte直接进行类型转换. 若进行操作,则可在计算时,先将 ...

  2. map集合排序

    默认情况下,HashMap.HashTable.TreeMap.LinkedHashMap的排列顺序比较: package com.per.sdg.demo; import java.util.Has ...

  3. 挖掘更合适的MVP模式的架构设计

        关于MVP,关于android,不得不说这篇博客已经来的非常晚了,这篇博客早就想写了,一直都在偷懒,就不给自己这么久的偷懒找借口了.尽管这篇文章po出来的比較晚.可是我所接触的程序猿一些朋友之 ...

  4. redis-3.0.3安装測试

    $ tar xzvf redis-3.0.3.tar.gz $ cd redis-3.0.3 $ make     //编译 编译完毕进行 $ make test 命令測试 得到例如以下错误信息: c ...

  5. asp.net项目与开源单点登录项目CAS的结合

    这段时间搞的一个asp.net mvc项目,采用了单点登录. 这个单点登录就是CAS,一个开源的JAVA项目.当然,这并不影响ASP.NET项目结合它来进行登录.因为各自分工不同:单点登录(管它是不是 ...

  6. flask的CBV,flash,Flask-Session,及WTForms-MoudelForm

    1,CBV: from flask import vews class LoginView(views.MethodView): def get(self): return "雪雪其实也很好 ...

  7. Hibernate 之 Locking

    在我们业务实现的过程中,往往会有这样的需求:保证数据访问的排他性,也就是我正在访问的数据,别人不能够访问,或者不能对我的数据进行操作.面对这样的需求,就需要通过一种机制来保证这些数据在一定的操作过程中 ...

  8. 在Android用ZXing.jar识别二维码的精简版(简化了配置和代码)

            近期公司做了一款OTP令牌激活的产品,因为之前激活手机令牌须要输入非常多的激活信息才干进行激活. 经过一段使用后,发现易用性不是非常强,考虑假设添加二维码的的扫码功能岂不是大大添加了易 ...

  9. HTML5中meta属性

    meta属性在HTML中占据了很重要的位置.如:针对搜索引擎的SEO,文档的字符编码,设置刷新缓存等.虽然一些网页可能没有使用meta,但是作为正规军,我们还是有必要了解一些meta的属性,并且能够熟 ...

  10. beego5---gosqlite安装

    WindowsWindows下的安装也非常简单,只要到 SQLite3 的下载页面,下载 Windows 下的预编译包 DLL 的压缩包(sqlite-dll-win32-x86-XXX.zip),然 ...