转: Android开发中的MVP架构详解(附加链接比较不错)
转: http://www.codeceo.com/article/android-mvp-artch.html
最近越来越多的人开始谈论架构。我周围的同事和工程师也是如此。尽管我还不是特别深入理解MVP和DDD,但是我们的新项目还是决定通过MVP来构建。
这篇文章是我通过研究和学习各种文章以及专题讨论所总结出来的,它包括以下几点:
- 为什么越来越多的人开始关注架构?
- 首先,MVP是什么?
- 哪种架构才是最好的,MVC,MVVM还是MVP?
- MVP的利与弊
- Show me the code!!!代码展示
不幸的,这篇文章将不包括:
- 详细生动的代码示例
- 如何编写测试代码
最后,我将告诉你如何更进一步学习这些专题。
顺便提一下,我于上周在当地的一个研讨会上对MVP架构进行了相关演讲。这篇文章与当时的演讲内容相差无几。
(译者注:阅读更多请点击原作者PPT)
介绍~Activity是上帝类~
首先,让我们思考一下为什么在Android开发中如此迫切地需要一个清晰的软件架构。
该段摘自“代码大全第二版”:
避免创建神类。避免创建无所不知,无所不能的上帝类。如果一个类需要花费时间从其他类中通过Get()和Set()检索数据(也就是说,需要深入业务并且告诉它们如何去做),所以是否应该把这些功能函数更好的组织到其它类而不是上帝类中。(Riel 1996)
上帝类的维护成本很高,你很难理解正在进行的操作,并且难以测试和扩展,这就是为什么要避免创建上帝类的黄金法则。
然而,在Android开发中,如果你不考虑架构的话,Activity类往往会越来越大。这是因为,在Android中,允许View和其它线程共存于Activity内。其实最大的问题莫过于在Activity中同时存在业务逻辑和UI逻辑。这会增加测试和维护的成本。
这是为什么需要清晰架构的原因之一。不仅会造成Activity的臃肿,还会引起其他问题,如使Activity和Fragment的生命周期变复杂,以及数据绑定等。
什么是MVP?
MVP代表Model,View和Presenter。
- View层负责处理用户事件和视图部分的展示。在Android中,它可能是Activity或者Fragment类。
- Model层负责访问数据。数据可以是远端的Server API,本地数据库或者SharedPreference等。
- Presenter层是连接(或适配)View和Model的桥梁。
下图是基于MVP架构的模式之一。View是UI线程。Presenter是View与Model之间的适配器。UseCase或者Domain在Model层中,负责从实体获取或载入数据。依赖规则如下:
关键是,高层接口不知道底层接口的细节,或者更准确地说,高层接口不能,不应该,并且必须不了解底层接口的细节,是(面向)抽象的,并且是细节隐藏的。
依赖规则?
Uncle Bob的“The Clean Architecture”描述了依赖的规则是什么。
同心圆将软件划分为不同的区域,一般的,随着层级的深入,软件的等级也就越高。外圆是实现机制,内圆是核心策略。
这是上面片文章的摘要:
Entities:
- 可以是一个持有方法函数的对象
- 可以是一组数据结构或方法函数
- 它并不重要,能在项目中被不同应用程序使用即可
Use Cases
- 包含特定于应用程序的业务规则
- 精心编排流入Entity或从Entity流出的数据
- 指挥Entity直接使用项目范围内的业务规则,从而实现Use Case的目标
Presenters,,Controllers
- 将Use Case和Entity中的数据转换成格式最方便的数据
- 外部系统,如数据库或网页能够方便的使用这些数据
- 完全包含GUI的MVC架构
External Interfaces, UI, DB
- 所有的细节所在
- 如数据库细节,Web框架细节,等等
MVC,MVP还是MVVM?
那么,哪一个才是最好的呢?哪一个比其他的更优秀呢?我能只选择一个吗?
答案是,NO。
这些模式的动机都是一样的。那就是如何避免复杂混乱的代码,让执行单元测试变得容易,创造高质量应用程序。就这样。
当然,远不止这三种架构模式。而且任何一种模式都不可能是银弹,他们只是架构模式之一,不是解决问题的唯一途径。这些只是方法、手段而不是目的、目标。
利与弊
OK,让我们回到MVP架构上。刚刚我们了解了什么是MVP,讨论了MVP以及其它热门架构,并且介绍了MVC,MVP和MVVM三者间的不同。这是关于MVP架构利与弊的总结:
**利
- 可测试(TDD)
- 可维护(代码复用)
- 容易Reviewe
- 信息隐蔽
**弊
- 冗余的,尤其是小型App开发
- (有可能)额外的学习曲线
- 开始编写代码之前需要时间成本(但是我敢打赌,设计架构是所有项目开发所必需的)
Show me the code!!!
这里仅展示了MVP模式的一小段结构。如果你想了解更多项目或生动的代码示例,请参考文章末尾的“链接和资源”。那里有非常丰富和设计巧妙的示例,基本都托管在Github上,以便你能clone,在设备上运行,并了解工作原理。
首先,为每一个View定义接口。
/**
* Interface classes for the Top view
*/
public interface TopView { /**
* Initialize the view.
*
* e.g. the facade-pattern method for handling all Actionbar settings
*/
void initViews(); /**
* Open {@link DatePickerDialog}
*/
void openDatePickerDialog(); /**
* Start ListActivity
*/
void startListActivity();
}
让我们重写TopView类,要点如下:
- TopActivity只是负责处理事件监听或者展示每个视图组件
- 所有的业务逻辑必须委托给Presenter类
- 在MVP中,View和Presenter是一 一对应的(在MVVM中是一对多的)
public class TopActivity extends Activity implements TopView { // here we use ButterKnife to inject views
/**
* Calendar Title
*/
@Bind(R.id.calendar_title)
TextView mCalendarTitle; private TopPresenter mTopPresenter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_top);
ButterKnife.bind(this); // Save TopPresenter instance in a meber variable field
mTopPresenter = new TopPresenter();
mTopPresenter.onCreate(this);
} /*
* Overrides method from the {@link TopView} interfaces
*/ @Override
public void initViews() {
// Actionbar settins // set event listeners
} @Override
public void openDatePickerDialog() {
DatePickerFragment.newInstance().show(getSupportFragmentManager(),
DatePickerFragment.TAG); // do not write logic here... all logic must be passed to the Presenter
mTopPresenter.updateCalendarDate();
} @Override
public void startListActivity() {
startActivity(new Intent(this, ListActivity.class));
}
}
这是Presenter类,最重要的一点是Presenter仅仅是连接View与Model的适配桥梁。比如,TopUseCase#saveCalendarDate()
是对TopPresenter细节隐藏的,同样对TopView也是如此。你不需要关心数据结构,也不需要关心业务逻辑是如何工作的。因此你可以对TopUseCase执行单元测试,因为业务逻辑与视图层是分离的。
ublic class TopPresenter { @Nullable
private TopView mView; private TopUseCase mUseCase; public TopPresenter() {
mUseCase = new TopUseCase();
} public void onCreate(@NonNull TopView topView) {
mView = topView; // here you call View's implemented methods
mView.initViews();
} public void updateCalendarDate() {
// do not forget to return if view instances is null
if (mView == null) {
return;
} // here logic comes
String dateToDisplay = mUseCase.getDateToDisplay(mContext.getResources());
mView.updateCalendarDate(dateToDisplay); // here you save date, and this logic is hidden in UseCase class
mUseCase.saveCalendarDate();
}
}
当然,尽管业务逻辑被实现在Activity类中,你依然可以执行单元测试,只不过这会耗费很多时间,而且有些复杂。可能需要更多的时间来运行App,相反,你本应该充分利用测试类库的性能,如Robolectric。
总结
这里没有万能药,而且MVP也仅仅是解决方案之一,它可以与其他方法协同使用,同样,也可以有选择的用于不同项目。
链接和资源
The Clean Architecture(译者注:清晰架构。译文) – Uncle Bob
这篇文章由Uncle Bob撰写,描述了依赖规则的样子和它们之间的组件是如何工作的。我从一开始谈论的那张图表的灵感就来源于他的文章,虽然这篇文章不是针对Android开发的,但是同往常一样,字里行间蕴藏着很多精辟的道理,所以,必读。
Architecting Android…The clean way? (译者注:Android中的清晰架构。译文)- Fernando Cejas
我认为这是在探索如何将MVP架构到Android开发专题中最著名,也是最受欢迎的博客。我也是从他那篇简单易读,书写良好的博客中偶然发现“MVP”这个名词的。他的示例代码托管在Github上,以便那些想要将MVP架构运用到正式App上的Android开发者clone到。
Android Architecture(译者注:Android架构) – Thanos Karpouzis
一个在Android项目中运用MVC,MVP,MVVM的简单指导。我从他的那篇普通却不平凡的文章中学到了很多,尤其是MVC,MVP和MVVM之间的不同。
Software Design patterns on Android English(译者注:Android开发中的软件设计模式) – Pedro Vicente Gómez Sánchez
这是一个在Karumi工作的高级Android开发工程师所讲的,他解释了一些MVP架构中的设计模式(如,渲染模式,仓库模式和命令模式)。如果你想深入理解MVC或者MVP,那这就使你要找的。
M — Model in MVC, MVP, MVVC in Android(译者注:MVC,MVP,MVVC架构中Model层在Android中的定义) – Artem Zinnatullin
如果你不还了解Model层中的JSON与SQL,或者不能透彻理解Model层的图像模型,这篇文章将带你进一步理解什么是Model层以及为什么Model层独立于其他层。其中“Model layer is solution”部分很好的解释了如何通过面向接口的方式编写测试。
转: Android开发中的MVP架构详解(附加链接比较不错)的更多相关文章
- 转:Android开发中的MVP架构(最后链接资源不错)
Android开发中的MVP架构 最近越来越多的人开始谈论架构.我周围的同事和工程师也是如此.尽管我还不是特别深入理解MVP和DDD,但是我们的新项目还是决定通过MVP来构建. 这篇文章是我通过研究和 ...
- 设计模式笔记之二:Android开发中的MVP架构(转)
写在前面,本博客来源于公众号文章:http://mp.weixin.qq.com/s?__biz=MzA3MDMyMjkzNg==&mid=402435540&idx=1&sn ...
- Android开发:文本控件详解——TextView(一)基本属性
一.简单实例: 新建的Android项目初始自带的Hello World!其实就是一个TextView. 在activity_main.xml中可以新建TextView,从左侧组件里拖拽到右侧预览界面 ...
- PHP开发中常见的安全问题详解和解决方法(如Sql注入、CSRF、Xss、CC等
页面导航: 首页 → 网络编程 → PHP编程 → php技巧 → 正文内容 PHP安全 PHP开发中常见的安全问题详解和解决方法(如Sql注入.CSRF.Xss.CC等) 作者: 字体:[增加 减小 ...
- Android开发:文本控件详解——TextView(二)文字跑马灯效果实现
一.需要使用的属性: 1.android:ellipsize 作用:若文字过长,控制该控件如何显示. 对于同样的文字“Android开发:文本控件详解——TextView(二)文字跑马灯效果实现”,不 ...
- Android开发5大布局方式详解
Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件. 帧布局(FrameLayout):组件从屏幕左上方布局组件. 表格布局(Tabl ...
- Android开发数据存储之ContentProvider详解
转载:十二.ContentProvider和Uri详解 一.使用ContentProvider(内容提供者)共享数据 ContentProvider在android中的作用是对外共享数据,也就是说你可 ...
- iOS开发中UIPopoverController的使用详解
这篇文章主要介绍了iOS开发中UIPopoverController的使用,代码基于传统的Objective-C,需要的朋友可以参考下 一.简单介绍 1.什么是UIPopoverController ...
- Java(Android)编程思想笔记03:在Android开发中使用MVP模式
1. MVP模式简介: MVC模式相信大家肯定是比较熟悉的:M-Model-模型.V-View-视图.C-Controller-控制器. MVP作为MVC的演化版本,那么类似的MVP所对应的意义:M- ...
随机推荐
- HTML5几种常见的错误写法
本文介绍了HTML5常见的6种错误写法,包括:1.不要使用section作为div的替代品 2.只在需要的时候使用header和hgroup 3.不要把所有列表式的链接放在nav里 4.figure元 ...
- JS与Jquery的事件委托——解决了绑定相同事件的问题
概念: 什么是事件委托:通俗的讲,事件就是onclick,onmouseover,onmouseout,等就是事件,委托呢,就是让别人来做,这个事件本来是加在某些元素上的,然而你却加到别人身上来做,完 ...
- 框架学习笔记:Unity3D的MVC框架——StrangeIoC
作为从AS3页游走过来的人,看见StrangeIoC会额外亲切,因为StrangeIoC的设计和RobotLegs几乎一致,作为一款依赖注入/控制反转(IoC)的MVC框架,StrangeIoC除了使 ...
- Javascript继承实现
S1:js中一切皆对象,想想如果要实现对父对象属性和方法的继承,最初我们会怎样子来实现呢,考虑到原型的概念,最初我是这样来实现继承的 function Parent(){ this.name='123 ...
- UVA1395
// UVa1395 Slim Span // Rujia Liu #include<cstdio> #include<cmath> #include<cstring&g ...
- mac 杂谈
========== 下载 -o 文件名:-O默认文件名保存 curl -o baidu.hml http://www.baidu.com curl -O http://su.bdimg.com/st ...
- nginx将http重定向到https
1.rewrite server { listen 80; server_name test.com; rewrite ^(.*)$ https://$host$1 permanent; } 2. n ...
- WIM更新命令(打补丁)
在D盘新建3个文件夹:win7(install.wim).updates(补丁).win7ultra 1.先打开ISO文件,然后加载映像到D:\win7ultra文件夹dism /mount-wim ...
- 【转】linux中的常见目录及文件
1. /proc目录 Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构.改变内核设置的机制.proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以 ...
- JavaScrip基础讲座 - 神奇的ProtoType
1. 什么是 prototype prototype 对于 JavaScript 的 意义重大,prototype 不仅仅是一种管理对象继承的机制,更是一种出色的设计思想 在现实生活中,我们常常说, ...