我们有可能使用过MVC(Model—View—Controller)模式,但当我们用更优的方法测试Android代码时,使用MVP(模型—视图—主导器:Model—View—Presenter)模式可能更合适。MVP模式与MVC模式的根本区别是:在MVP模式中,视图中的业务逻辑被放入主导器中,主导器通过接口与视图交互。在MVC模式中,视图可以包含访问模型的逻辑。在MVP模式中,视图与模型是隔离的,所有与视图和模型的交互操作都是在主导器中完成,因此主导器在整个MVP模式中处于“主导”地位。

在接下来的demo里,我会展示如何在Android中使用MVP模式,以及如何利用该模式提高代码的易测性。为了演示其运行机制,我们创建一个启动画面。所谓启动画面,就是一个普通的界面,在应用程序开始运行前做一些初始化和验证工作。在本例中,我们会在启动画面中检查网络连接是否正常,并显示一个进度条。如果网络连接正常,就切换到另一个Activity中;否则便不会切换到其他Activity,而是向用户显示一条错误信息以阻止程序继续运行。

要创建启动画面,需要一个负责在模型和视图间交互的主导器。在本例中,主导器有两个功能:一个功能用于判断网络是否连接,另一个功能用于控制视图。

主导器中会用到一个模型类ConnectionStatus,该类实现了IConnectionStatus接口,该接口中只定义了一个判断网络是否在线的方法。源码如下所示:

public interface IConnectionStatus {boolean isOnline();
}

负责控制视图的代码位于Activity中,并且这个Activity实现了ISplashView接口。主导器会通过该接口控制应用程序的执行过程。ISplashView接口的源码如下所示:

public interface ISplashView {void showProgress();void hideProgress();void showNoInetErrorMsg();void moveToMainView();
}

因为我们是在Android平台上开发应用程序,因此首先需要创建视图,然后我们会把视图的控制权交给主导器。代码如下所示:

public class SplashActivity extends Activity implements ISplashView {private TextView mTextView;private ProgressBar mProgressBar;private SplashPresenter mPresenter;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.splash);//为当前Activity初始化主导器,并将当前Activity设置给主导器mPresenter = new SplashPresenter();mPresenter.setView(this);//Activity初始化代码mTextView = (TextView) findViewById(R.id.splash_text);mProgressBar = (ProgressBar) findViewById(R.id.splash_progress_bar);}@Overrideprotected void onResume() {super.onResume();//运行onResume()方法时,通知主导器当前视图已经准备完毕,可以把控制权交给主导器了mPresenter.didFinishLoading();}@Overridepublic void showProgress() {mProgressBar.setVisibility(View.VISIBLE);}@Overridepublic void hideProgress() {mProgressBar.setVisibility(View.INVISIBLE);}@Overridepublic void showNoInetErrorMsg() {mTextView.setText("No internet");}@Overridepublic void moveToMainView() {startActivity(new Intent(this, MainActivity.class));}
}

主导器的代码比较简单,其源码如下所示:

public class SplashPresenter {private IConnectionStatus mConnectionStatus;private ISplashView mView;public SplashPresenter() {this(new ConnectionStatus());}public SplashPresenter(IConnectionStatus connectionStatus) {mConnectionStatus = connectionStatus;}public void setView(ISplashView view) {this.mView = view;}protected ISplashView getView() {return mView;}public void didFinishLoading() {//获取视图,即设置给主导器的ISplashView接口的实现类的引用ISplashView view = getView();//判断程序是否继续执行的逻辑if (mConnectionStatus.isOnline()) {view.moveToMainView();} else {view.hideProgress();view.showNoInetErrorMsg();}}
}

从上述代码可以看出,主导器通过接口访问视图,主导器并不知道该接口是由Activity实现的。这样,在单元测试中就更容易模拟(mock)视图。

MVP模式可以使代码更易组织且更易测试。在上述demo中,有一个测试文件夹,在测试代码中需要初始化主导器并模拟(mock)接口。在主导器中并未使用任何Android平台相关的代码,因此不需要在Android设备生运行测试用例,只需要在JVM上运行即可。此外,在本例中我们使用Mockito模拟接口。

在Android平台上开发应用程序,我们会发现Activity中会存在大量代码。遗憾的是,测试Activity是很痛苦的。使用MVP模式不仅可以简化创建测试用例的过程,还可以更容易地实施TDD(test-driven development,测试驱动开发)。

代码地址

Android开发模式:模型—视图—主导器模式相关推荐

  1. python设计模式【8】-模型·视图·控制器-复合模式

    UML类图简介 设计模式的分类 面向对象的设计原则 python设计模式[1]-单例模式 python设计模式[2]-工厂模式 python设计模式[3]-门面模式 python设计模式[4]-代理模 ...

  2. Android开发笔记(九十)建造者模式

    基本概念 建造者模式是一种常用的设计模式,它用于把类的表现和构建分离开来.引入建造者模式的缘由,且看博主下面细细道来. 公开属性 一般我们定义一个类的属性,如果属性是公开的,那可以直接对该类的属性赋值 ...

  3. 【实例学模式】一针见血装饰器模式

    目录 什么是装饰器模式 开发案例[奶茶店自助下单系统] 设计方案 对装饰器模式的思考 什么是装饰器模式 通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合 ...

  4. 7.SpringMVC 配置式开发-ModelAndView和视图解析器

    ModelAndView 1.Model(模型) 1.model的本质就是HashMap,向模型中添加数据,就是往HashMap中去添加数据 2.HashMap 是一个单向查找数组,单向链表数组 3. ...

  5. php装饰器模式 简书,装饰器模式/包装器模式

    在电视剧<相爱十年>中,主角肖然把出现了品控问题的安尔雅肥皂换了个包装.改了套说辞变成了全新的品牌浴雪清,并成功的推销出去了,得到了第一桶金.这就说所谓的包装,本质上并没有改变,但是外在表 ...

  6. android开发监听媒体播放器,Android开发之媒体播放工具类完整示例

    本文实例讲述了Android开发之媒体播放工具类.分享给大家供大家参考,具体如下: package com.maobang.imsdk.util; import android.media.Media ...

  7. php 解析器模式,娓娓道来:解析器模式-interpreter

    解析器模式:解析脚本的语言解析器. php源于c语言,其实是用c语言解析了php脚本,那么php有是如何解析其他语言的呢,看看面向对象的魅力所在吧. 现在解析这样一句话: $input equals ...

  8. 6中结构型设计模式的对比理解(Composite组合模式,Proxy代理模式,Flyweight享元模式,Facade门面模式,Bridge桥接模式,Decorator装饰器模式)

    结构型模式 结构型模式用来组装 类和对象,以获得更大的结构. 结构型类模式,通过继承机制来组合接口或类.简单的例子就是多重继承,最后一个类拥有所有父类的性质.这个模式有助于独立开发一个协同类.另一个例 ...

  9. Android开发之本地音乐播放器(二)

    此次音乐播放器是针对上一个:https://blog.csdn.net/qq_43433255/article/details/88084420 开发出来的一个功能增强型,基本实现功能为: 通过列表管 ...

最新文章

  1. ACM/OI卡常技巧总结(clock大法好)
  2. JAVA常见面试题之Error、RuntimeException、CheCkedException
  3. Indesign CS6怎么添加框线_InDesign小小知识库
  4. java reactor例子_ProjectReactor响应式编程入门例子
  5. 嵌入式linux实验一vim的使用,嵌入式Linux C语言开发工具—vi/vim实训操作
  6. ndr4108贴片晶振是多少频率_流处理器、核心频率、 位宽……这些显卡参数你知道吗?—— 电脑硬件科普篇(八)...
  7. 剑指offer面试题13:O(1)删除链表结点
  8. rant c语言头文件,用CGIC库来开发CGI程序
  9. 网站扫码登录时怎么一回事?
  10. 第十四届恩智浦智能车竞赛小白四轮硬件总结
  11. Spring Boot配置MongoDB多数据源
  12. C51 数码管的动态显示 dynamic display method of digital tube
  13. Latex常见数学符号写法
  14. CLOUD01 - KVM构建及管理 virsh控制工具、镜像管理 虚拟机快建技术
  15. php中的or die,php or die() 语句,exit()
  16. php spry文本域_SPRY验证文本域之用户名称
  17. excel 将隔行空白单元格填充为最靠近上面且有值的单元格的数据
  18. 【数据压缩】TGA文件格式分析
  19. 算法复习——动态规划篇之最长公共子序列问题
  20. CAD对块的文字操作

热门文章

  1. python输出宽度是什么意思_python字符串格式化输出的时候类似{0:.3f}是什么意思?...
  2. 泰雷兹推出未来飞机的大脑PureFlyt
  3. 哪个大学有计算机专业博士授权,哪些学校有计算机应用博士点
  4. php两个数字进行比较大小
  5. hadoop-mapreduce-4
  6. php判断caj文件页数,2个免费CAJ转PDF的方法,而且不限页数和大小
  7. FI中常用表和凭证类型
  8. 后勤管理系统—服务台管理功能
  9. python读文件的三种方式_Python|读、写Excel文件(三种模块三种方式)
  10. 凯文.柯恩《真爱无尽精选辑》