在Android开发中,我们常常会动辄写出数千行的Java类,而当一个Activity有4、5千行的时候,想找一个逻辑在哪儿就会显得异常痛苦了。比如想在数据加载错误的时候,显示一个提示信息,上上下下得找很久。

最近用了MVP模式后,我觉得找到了一个不错的框架级解决方法。

首先看看

MVP是什么

MVP是MVC模式的一个衍生物,可以简单看下图。在MVP模式中,V层完全和M层(在Android中可能是Model、DAO、或者通用的business logic)分开。在中间用P层分隔,从而把数据有关和UI有关完全分离开。

主流的MVP又有两种实现方式

1)Activity、Fragment、View直接作为V层。Presenter通过继承被视图层实例化或者通过注入得到。这样Presenter在理想状态下可以完全和Android分离,也剥离了activity的那些生命周期。

2)Activity和Fragment作为P层,另外单独创建一个V层类,持有Activity里面的各种view,并提供接口让Activity调用来更新界面。

为了让V层和P层解耦,通常P层对V层的持有是通过interface的。

一个完整的mvp事件流可以是

sample

这里用第一种实现方式来做个例子。

每个Activity继承的基类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* A {@link BaseActivity} that uses an {@link MvpPresenter} to implement a MVP Architecture.
*/
public abstract class MvpActivity<P extends MvpPresenter> extends BaseActivity implements MvpView { protected P presenter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter = createPresenter();
if (presenter == null) {
throw new NullPointerException("Presenter is null");
}
presenter.attachView(this);
} @Override
protected void onDestroy() {
super.onDestroy();
presenter.detachView(false);
} /**
* Instantiate a presenter instance
*
* @return The {@link MvpPresenter} for this view
*/
protected abstract P createPresenter();
}

暴露给Presenter的View层接口:

1
2
3
4
5
/**
* The root view interface for every mvp view
*/
public interface MvpView {
}

Presenter层,告别了繁琐的activity周期,只有创建和销毁两个状态接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* The base interface for each mvp presenter
*/
public interface MvpPresenter<V extends MvpView> { /**
* Set or attach the view to this presenter
*/
void attachView(V view); /**
* Will be called if the view has been destroyed. Typically this method will be invoked from
* <code>Activity.detachView()</code> or <code>Fragment.onDestroyView()</code>
*/
void detachView(boolean retainInstance);
}

比如这次做新的留言板需求,我就写了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class QZoneLeaveMessageActivity extends MvpActivity<LeaveMessagePresenter> implements LeaveMessageView, OnClickListener {

}
// Lce就是Load Content Error,通用的load数据View接口
public interface MvpLceView<M> extends MvpView {
void showLoading(boolean pullToRefresh);
void showContent();
void showError(Throwable e, boolean pullToRefresh);
void setData(M data);
void loadData(boolean pullToRefresh);
} public interface LeaveMessageView extends MvpLceView<List<TemplateData>> {
...
}
public class LeaveMessagePresenter extends MvpBasePresenter<LeaveMessageView> implements QZoneServiceCallback {
}

这么些类来应用了MVP模式,个人觉得是比以前清晰了不少。

个人心得

  • 不要把presenter当做OnClickListener,View才是来处理用户输入和给予反馈的,presenter不应该知道view内部的逻辑来判断点击某个按钮后做出什么相应。一个简单的判断某个逻辑是否属于presenter的方法是,如果view层不是android,而是java桌面应用,那你的presenter层是不是还能不做更改地work。
  • view层只做presenter层让你做的,比如上图view层用户点了一个按钮,View调用了presenter.loadUsers,presenter一边在background thread去getUsers,一边调用了view.showLoading(),view层不该自说自话地showLoading。不过如何showLoading,比如展示怎么样的动画,那就是view层的内部矛盾了。
  • 一个很大的好处,就是通过MVP,异步变得很清晰,view层的东西完全是主线程的,只需要等着presenter调就行了。

应用MVP模式写出可维护的优美Android应用的更多相关文章

  1. 《JS高程》-教你如何写出可维护的代码

    1.前言   在平时工作开发中,大部分开发人员都花费大量的时间在维护其他人员的代码.很难从头开始开发新代码,很多情况下都是以他人成果为基础的,或者新增修改需求,自己写的代码也会被其他开发人员调用,所以 ...

  2. Android MVP模式

    转自http://segmentfault.com/blogs,转载请注明出处Android MVP Pattern Android MVP模式\[1\]也不是什么新鲜的东西了,我在自己的项目里也普遍 ...

  3. Android开发之初识MVP模式

    各位亲爱的小伙伴,有没有想我啊,我胡汉wing又回来了. 很长一段时间没有更新博客..原因是..从离职回到学校以后,一直在享受最后的学生时光(打游戏).. 游戏固然很爽,但是觉得实在很荒废,于是半夜诈 ...

  4. Android MVP模式 谷歌官方代码解读

    Google官方MVP Sample代码解读 关于Android程序的构架, 当前(2016.10)最流行的模式即为MVP模式, Google官方提供了Sample代码来展示这种模式的用法. Repo ...

  5. 从最简单的HelloWorld理解MVP模式

    版权声明:本文为博主原创文章,转载请注明出处:http://www.cnblogs.com/joy99/p/6116855.html 大多数编程语言相关的学习书籍,都会以hello,world这个典型 ...

  6. .Net平台-MVP模式再探(二)

    PS:     本文与  上一遍文章  没有什么必然的联系,可以说是对于MVP的一定的加深,或许在理解上比上一篇多有点难度. 正文   一.简单讲讲MVP是什么玩意儿 如果从层次关系来讲,MVP属于P ...

  7. .Net平台-MVP模式初探(一)

    为什么要写这篇文章 笔者当前正在负责研究所中一个项目,这个项目基于.NET平台,初步拟采用C/S部署体系,所以选择了Windows Forms作为其UI.经过几此迭代,我们发现了一个问题:虽然业务逻辑 ...

  8. 如何从MVP模式进阶到Clean模式

    从类图上来看,MVP都是一个业务一个Presenter,每个Presenter都是一个接口,它还包含了View的接口,用于定于和View相关的行为,然后Activity等业务类实现View的接口,因为 ...

  9. 说说Android的MVP模式

    http://toughcoder.NET/blog/2015/11/29/understanding-Android-mvp-pattern/ 安卓应用开发是一个看似容易,实则很难的一门苦活儿.上手 ...

随机推荐

  1. SharedPreference.Editor的apply与commit方法不同之处

    定义: void apply boolean commit; 相同:二者都是提交修改的数据 手机里的文件存放在/data/data/<package_name>/shared_prefs ...

  2. Session_set_save_handler 之 文本模式实现

    1.构建session抽象类,实现Session_set_save_hanlder函数必须的基础函数 <?php /* 实现session利用文件形式或者数据库等其它形式进行存储操作 * aut ...

  3. JS禁用浏览器退格键

    我们在真实的项目开发中经常会使用JS 对键盘上的一些按键进行禁用,常见的比如说退格键(backspace/ 后退键),我在一个项目中就遇到过在页面编辑的时候禁用掉退格键,因为退格键会发生页面后退,代码 ...

  4. fineui框架

    http://fineui.com/demo/#/demo/layout/fit.aspx 虽然比较丑陋,但功能实用 此框架比较简单, 框架的作用你懂的,重点是要有帮助文档, 进阶型的容易上手的帮助文 ...

  5. 第一个js面向对象的小实验

    $.extend({             cal: function (num1,num2,oper,aftercal) {                 this.n1 = num1;     ...

  6. SQL优化之索引

    最近碰到一个问题,因数据量越来越大,然后存储过程查询过慢!后来发现没有加索引列导致的!从这里让我开始慢慢去了解索引的原理及作用!以下是我的总结,个人理解只供参考: SQL SERVER提供了两种索引: ...

  7. bnu 4353 删格游戏(博弈)

    http://www.bnuoj.com/bnuoj/problem_show.php?pid=4353 [题意]:每次选择一个小格后,该小格的右上部分就全被删去了,且要求每次至少删去一个格子,选中左 ...

  8. 根据不同ip进入不同页面

    function GetIP() { $cip = ""; if(!empty($_SERVER["HTTP_CLIENT_IP"])){ $cip = $_S ...

  9. sql视图学习笔记--视图

    视图是为用户对数据多种显示需求而创建的,其主要用在一下几种情况: (1)限制用户只能访问特定表特定条件的内容,提高系统的安全性. (2)隐藏表结构.创建多种形式的数透视,满足不同用户需求. (3)将复 ...

  10. 1588: [HNOI2002]营业额统计 - BZOJ

    Description营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天 ...