摘要: 在MVVM成熟之前MVP模式在Android上有被神化的趋势,笔者曾经在商业项目中从零开始大规模采用过MVP模式对项目进行开发。在使用MVP模式进行开发的时候发现项目的结构模式对开发是有一定的影响的,在这里笔者会对这一问题进行探讨。希望通过这篇blog能让读者了解如何使用MVP模式搭建一个功能完善的MVP模式开发框架,避免一些笔者认为比较严重的问题。

为什么要使用MVP模式

在传统的Android开发中,我们一般是使用MVC模式进行开发的。
传统MVC模式介绍:

  1. View: 视图层,对应xml文件
  2. Controller: 控制层,对应Activity和Fragment层,进行数据处理
  3. Model:实体层,负责获取实体数据

在Android开发中采用MVC模式的一个最大的弊端就是xml作为View层视图能力实在太弱,所以一般情况下我们都是通过Controller层来辅助处理一些视图的。这样的结果就导致Controller既作为控制层的同时又承担了View层的大部分功能,采用MVC模式往往会导致Activity和Fragment中的代码非常复杂。我们将Android中采用的MVC模式称为MV模式更加恰当。

MVP模式介绍:

  1. View: 视图层,对应xml文件与Activity/Fragment
  2. Presenter: 逻辑控制层,同时持有View和Model对象
  3. Model: 实体层,负责获取实体数据

MVP模式的流程图如下:

MVP模式图解

采用MVP模式的优势是:

  1. 把业务逻辑抽离到Presenter层中,View层专注于UI的处理。
  2. 分离视图逻辑与业务逻辑,达到解耦的目的。
  3. 提高代码的阅读性。
  4. Presenter被抽象成接口,可以根据Presenter的实现方式进行单元测试。
  5. 可拓展性强。

采用MVP模式的缺点:

  1. 项目结构会对后期的开发和维护有一定的影响。具体视APP的体量而定。
  2. 代码量会增多,如何避免编写过多功能相似的重复代码是使用MVP开发的一个重点要处理的问题。
  3. 有一定的学习成本。

综上所述,在Android上采用MVP模式的优势是:大大优化代码的维护性与拓展性的同时对代码进行深度解耦,使各个层级的分工更加明晰。

Android上MVP模式的简单应用

先来看看一个简单用mvp模式模拟登陆的demo,下面的示例代码和其它简单介绍MVP模式的代码没有太大区别。如果有了解过的同学可以直接跳过看下一章关于如何优化MVP模式的结构的文章。

下面我们来看看在Android上用MVP模式实现简单的登录逻辑的方式:

. 登陆界面

登陆界面

  1. 项目的结构:

    项目结构

从上面的代码结构图可看出,用MVP模式实现登陆模块需要创建6个文件,分别是M、V、P接口文件和接口的对应实现。其中LoginActivity就是View层的具体实现。这样的好处时Activity组件只需要负责处理UI相关逻辑就可以了,而相关的业务逻辑全部抽象到Presenter层中处理。通过这种方式能够很好的避免传统Android开发中的Activity/Fragment等UI组件既负责处理UI逻辑又处理业务逻辑的结果。

. 代码实现

说了这么多,最后我们来看看代码的实现吧。

  1. ILoginModel

    1
    2
    3
    public interface ILoginModel {
    void login(String name ,String password);
    }
  2. ILoginPresenter

    1
    2
    3
    4
    5
    6
    public interface ILoginPresenter {
     
    void loginToServer(String userName,String password);
     
    void loginSucceed();
    }
  3. ILoginView

    1
    2
    3
    4
    5
    6
    public interface ILoginView {
     
    void showProgress(boolean enable);
     
    void showLoginView();
    }

上面是登陆模块对应的MVP接口的具体设计,下面我来简单介绍一下接口中的几个方法:

  • ILoginModel.login(String name ,String password)登陆方法,通过该方法向服务器发送登陆请求。
  • ILoginPresenter. loginToServer (String name ,String password)通知Model响应登陆事件。
  • ILoginPresenter. loginSucceed()当登陆事件完成时(成功/失败),Model层要通知该方法登陆事件已完成。
  • ILoginView. showProgress(boolean enable)当Presenter层调用loginToServer (String name ,String password)方法时,要通过该方法通知View层显示加载动画。
  • ILoginView. showLoginView()登陆成功时,Presenter层会通过该方法通知View层登陆已成功。

下面我们来看看这几个接口的具体实现。

  1. LoginModel

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class LoginModel implements ILoginModel{
     
    private ILoginPresenter presenter;
     
    private Handler mHandler = new Handler();
     
    public LoginModel(ILoginPresenter presenter) {
    this.presenter = presenter;
     
    }
     
    @Override
    public void login(String name ,String password) {
    mHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
    Log.d("LoginModel", "run: ");
    presenter.loginSucceed();
    }
    },2000);
    }
     
    }

上面的Model层实现了login(String name,Stringpassword)登陆方法,该方法的具体实现逻辑是通过线程休眠2秒来模拟网络登陆的过程,登陆成功后会通过LoginPresenter的loginSucceed()方法来通知Presenter层登陆结果。实际开发中我们需要根据具体的业务逻辑来实现该过程。

  1. LoginPresenter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class LoginPresenter implements ILoginPresenter{
     
    private ILoginModel loginModel;
     
    private ILoginView loginView;
     
    public LoginPresenter(ILoginView loginView) {
    this.loginView = loginView;
    this.loginModel = new LoginModel(this);
    }
     
    @Override
    public void loginToServer(String userName, String password) {
    loginView.showProgress(true);
    loginModel.login(userName,password);
    }
     
    @Override
    public void loginSucceed() {
    loginView.showProgress(false);
    loginView.showLoginView();
    }
    }

从上面代码可以看出LoginPresenter的实现逻辑很简单,首先在构造方法中获取ILoginView对象并撞见ILoginModel对象。然后当View层调用loginToServer(String userName, String password)方法成功时,通知View层显示加载动画并调用ILoginModel层的login(String userName, String password)方法向服务器发送登陆请求。当登陆成功后(即Model层通知loginSucceed方法时)通过loginView.showProgress(false)方法通知View层隐藏加载动画,并通知View登陆成功。

  1. LoginActivity
    对于LoginActivity我们只需要关注其中的几个方法即可

    1
    2
    3
    4
    5
    6
    7
    loginBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    //模拟登陆,不需要账号密码
    loginPresenter.loginToServer("","");
    }
    });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
public void showProgress(boolean enable) {
if (enable){
progressBar.setVisibility(View.VISIBLE);
loginLayout.setVisibility(View.GONE);
}else {
progressBar.setVisibility(View.GONE);
loginLayout.setVisibility(View.VISIBLE);
}
}
 
@Override
public void showLoginView() {
Toast.makeText(LoginActivity.this,"登陆功",Toast.LENGTHSHORT).show();
finish();
}

上面时实现了ILoginView接口的两个方法。
结合上面的代码可以看出,当点击登陆按钮的监听事件时,我们不需要关注业务逻辑,只需要调用loginPresenter.loginToServer("","");方法即可,然后根据实际情况实现View层中ILoginView接口的方法即可,这样达到了UI业务与逻辑完全分离的目的。

Android架构篇--MVP模式的介绍篇的更多相关文章

  1. [译]Google官方关于Android架构中MVP模式的示例

    概述 该示例(TODO-MVP)是后续各种示例演变的基础,它主要演示了在不带架构性框架的情况下实现M-V-P模式.其采用手动依赖注入的方式来提供本地数据源和远程数据源仓库.异步任务通过回调处理. 注意 ...

  2. Google官方关于Android架构中MVP模式的示例续-DataBinding

    基于前面的TODO示例,使用Data Binding库来显示数据并绑定UI元素的响应动作. 这个示例并未严格遵循 Model-View-ViewModel 或 Model-View-Presenter ...

  3. 如何结合整洁架构和MVP模式提升前端开发体验 - 整体架构篇

    本文不详细介绍什么是整洁架构以及 MVP 模式,自行查看文章结尾相关链接文章. 整洁架构粗略介绍 下图为整洁架构最原始的结构图: Entities/Models:实体层,官方说法就是封装了企业里最通用 ...

  4. Android MVP模式简单易懂的介绍方式 (二)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 上一篇文章我们介绍完了Model的创建 ...

  5. DDD分层架构之值对象(介绍篇)

    DDD分层架构之值对象(介绍篇) 前面介绍了DDD分层架构的实体,并完成了实体层超类型的开发,同时提供了验证方面的支持.本篇将介绍另一个重要的构造块——值对象,它是聚合中的主要成分. 如果说你已经在使 ...

  6. Android MVP模式 简单易懂的介绍方式

    主要学习这位大神的博客:简而易懂 Android MVP模式 简单易懂的介绍方式 https://segmentfault.com/a/1190000003927200

  7. Android MVP模式简单易懂的介绍方式 (三)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 讲完M和P,接下来就要讲V了.View ...

  8. Android MVP模式简单易懂的介绍方式 (一)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 最近正在研究Android的MVP模式 ...

  9. 浅谈Android架构之MVP,MVVM

    概述 MVP(Model-View-Presenter)是传统MVC(Model-View-Controller)在Android开发上的一种变种.进化模式.主要用来隔离UI.UI逻辑和业务逻辑.数据 ...

随机推荐

  1. Swift5 语言指南(十) 枚举

    一个枚举定义了一个通用型的一组相关的值,使你在你的代码中的一个类型安全的方式这些值来工作. 如果您熟悉C,您将知道C枚举将相关名称分配给一组整数值.Swift中的枚举更灵活,并且不必为枚举的每个案例提 ...

  2. Qt之实现网络下发配置的半透明友好提示界面

    一.说明 在使用Qt开发的网管客户端程序中,网管客户端主要负责显示设备信息以及对设备下发配置信息等,如配置设备名字.更新设备程序等:由于在网管客户端程序的操作要先经过服务器处理,再由服务器将该命令转发 ...

  3. interface中定义default方法和static方法

    interface的default方法和static方法 接口中可以定义static方法,可通过接口名称.方法名()调用,实现类不能继承static方法: 接口中可以定义default方法,defau ...

  4. Tools - Windows OS

    001 - 文本操作 Ctrl + C / Ctrl + V / Ctrl + X / Ctrl + Z / Ctrl + A:复制/粘贴/剪贴/撤销/全选. 002 - 窗口分屏 使用快捷键 选中程 ...

  5. MySQL 中的数字类型

    MySQL 中数据类型常用的就三大类: 数字类型/numeric types 日期和时间/date and time types 字符类型/string (character and byte) ty ...

  6. 关于 Spring Security 5 默认使用 Password Hash 算法

    账户密码存储的安全性是一个很老的话题,但还是会频频发生,一般的做法是 SHA256(userInputpwd+globalsalt+usersalt) 并设置密码时时要求长度与大小写组合,一般这样设计 ...

  7. IDEA中SpringBoot项目快速创建单元测试

    如何在IDEA中对于SpringBoot项目快速创建单元测试 创建测试用例 右键需要进行测试的方法,选择GO TO然后选择Test 点击Create New Test 勾选需要创建单元测试的方法 然后 ...

  8. Eureka安全认证

    Eureka 服务加入安全认证只需要在之前的服务中增加三处步骤即可: 1.在Eureka Server中加入spring-boot-starter-security依赖 <dependencie ...

  9. 使用InstallUtil发布windows服务

    发布Windows Service的方法 1. 在默认窗口Service1中右键Add Install,自动生成两个类. 2. 修改serviceInstaller1的属性:  a)ServiceNa ...

  10. 深入JAVA注解(Annotation):自定义注解 (转)

    原文出自:http://blog.csdn.net/yjclsx/article/details/52101922 一.基础知识:元注解 要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义 ...