在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. [Learn Android Studio 汉化教程]第四章 : Refactoring Code

    [Learn Android Studio 汉化教程]第四章 : Refactoring Code 第四章 Refactoring Code    重构代码 在Android Studio中开发,解决 ...

  2. easy ui easyui-linkbutton 禁用、启用

    <a id="btn_update_Shop" name="btn_update_Shop" class="easyui-linkbutton& ...

  3. 如何让VS根据编译环境选择相应的配置文件

    其实微软还是蛮有创造力的,一个配置文件居然弄了这么多的形式,从原来的ini到现在的xml,总而言之让我们这些在微软殿堂里的程序员翘着屁股追赶. 微软最新的配置文件实际上就是个xml文件,以后缀名.co ...

  4. 基于Ogre的DeferredShading(延迟渲染)的实现以及应用

    http://blog.sina.com.cn/s/blog_458f871201017i06.html 这篇文章写的不错,从比较宏观的角度说了下作者在OGRE中实现的延迟渲染

  5. java第三课:分支结构、循环结构

    分支结构 1.if后面可以不加{},但是不建议,容易产生误解2.写程序的时候先防屌丝测试,再写逻辑,否则会出错3.if:一条分支 if else:两条分支 if...else if...:多条分支(结 ...

  6. Java 类加载机制 ClassLoader Class.forName 内存管理 垃圾回收GC

    [转载] :http://my.oschina.net/rouchongzi/blog/171046 Java之类加载机制 类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指 ...

  7. PD 脚本中列名注释用Name属性

    操作步骤:Database=>Generate Datatabase=>Format选项卡=>勾选 Generate name in empty comment项

  8. 1053: [HAOI2007]反素数ant - BZOJ

    Description 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4. 如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数 ...

  9. BZOJ 3288 Mato矩阵 解题报告

    这个题好神呀..Orz taorunz 有一个结论,这个结论感觉很优美: $$ans = \prod_{i=1}^{n}\varphi(i)$$ 至于为什么呢,大概是这样子的: 对于每个数字 $x$, ...

  10. VB断点大全

    MultiByteToWideChar, ANSI字符串转换成Unicode字符串WideCharToMultiByte, Unicode字符串转换成ANSI字符串 //--------------- ...