原文地址:

http://engineering.remind.com/android-code-that-scales/

Demo

https://github.com/remind101/android-arch-sample

写一个Hello World程序总是很简单的,它的代码总是很简单、整齐的,SDK完全可以满足我们的需求。但是,如果你在开发过复杂的Android app,你应该清楚,生产环境的代码往往不是这样。你需要不断的在已经很复杂的Activity 的onCreate 方法里面去添加if 语句去解决app在某个设备奔溃的问题,或者添加一些额外的业务逻辑。
我们每两周就会需要添加一些新的需求,为了能够维持产品开发的速度和质量,我们需要让我们的代码简单,可维护,耦合性低,容易测试。使用MVP架构模式可以帮助我们实现这个需求,让我们能够把精力集中到业务逻辑上面。MVP,全称Model-View-Presenter,是一种提升分离交互关系的多功能模式,和其他的模式有些轻微的不同。这篇文章的目标不是其描述MVP与其他模式的区别,而是展示如何把它应用到我们Android应用开发过程中,让我们的app受益。

Android 原有模式

Android 设计的分层是这样的,Model 层是实体类,View层是XML布局,Controller层是Activity,Fragment。理论上,这种模式工作得很好,但是,当你的app变得复杂,那么在你的Controller里面有大量的View代码,因为你需要处理数据绑定,动画,输入检查,事件监听,当然,还包括你的业务逻辑的代码。如果这些复杂的界面放在List或者Grid中,那情况就更坏了,Adapter不仅仅包含着View层和Controller层的代码,而且需要把它们当集合维护,这些模块都是高度耦合的,很难去维护和测试。

MVP模式

MVP 提供了一种方法,可以分离出冗长的控件显示和UI交互的Android代码,放到View层中,把业务逻辑的的代码放到Presenter中。Android中实现MVP方法的是,把Activity和Fragment看做是View层,用一个轻量级的Presenter去控制。最关键的地方是确立每一层的职责,并且使它们的接口规范化。下面是一些分层的规则:

View(Activity or Fragment)层的职责:

  • 初始化Presenter,绑定,和解绑Presenter
  • 通知Presenter 有关生命周期的方法
  • 通知Presenter输入事件
  • 初始化View,为View绑定数据
  • 动画
  • 事件跟踪
  • 界面跳转

Presenter职责:

  • 加载实体数据
  • 持有model 和view 的引用
  • 处理数据,并交给View层显示
  • 和数据库,网络交互
  • 处理UI事件

下面是View层和Presenter层的接口示例:

View:

interface MessageView { // View methods should be directives, as the View is just executing orders from the Presenter. // Methods for updating the view void setMessageBody(String body); void setAuthorName(String name);void showTranslationButton(boolean shouldShow); // Navigation methods void goToUserProfile(User user);}

Presenter:

interface MessagePresenter { // Presenter methods should mostly be callbacks, as the View is reporting events for the// Presenter to evaluate // Lifecycle events methods void onStart();// Input events methods void onAuthorClicked();void onThreeFingersSwipe();}

下面是一些关于这些接口的讨论:

  • 更新View的方法必须是简单的,并且作用在一个目标view上面,这比一个setMessage方法去更新所有的view好。因为决定哪个信息放到view上面属于业务逻辑,应该放到Presenter中去处理,例如,当作者就是当前用户时,你想显示”你”代替用户名显示到view上面,着属于业务逻辑。
  • Presenter中的生命周期方法没有必要完全和Activity或者Fragment中的生命周期方法去匹配,只实现需要做处理的相关方法。
  • View监听到点击事件时先调用Presenter中的onAuthorClicked ,然后Presenter再调用goToAuthorProfile,不能在View中调用goToAuthorProfile()方法,因为决定去profile属于业务逻辑,应该放在Presenter中处理。

在MVP规则中,你的Presenter层的代码包含了Android Framework中的代码,而不是纯Java,那么你一定是某个地方写错了。同样,如果你的View层的代码持有Model层的引用,那么也是错误的。

在测试中,大部分需要测试的代码应该在Presenter中,最大的好处是这些代码不需要Android环境去运行,因为Presenter只持有View的引用,没有Android 相关代码的实现。这意味着我们能模拟一个View的接口,写纯JUnits测试,确保业务逻辑运行正确

List列表

到目前为止,我们猜想View层是Activity和Fragment,其实使用ViewHolder(不管是RecyclerView.ViewHolder还是List的ViewHolder )实现View的接口也可以正确的工作,在Adapter中,你只需要实现一些简单的逻辑,包括绑定和解绑Presenter。假设你的界面上有一个消息列表,一个加载的进度条,和数据为空时的界面,那么应该向下面这样分离:

  • list 的Presenter 负责加载消息逻辑,展示消息 list/empty/loading的逻辑
  • Fragment或者Activity负责 消息 list/empty/loadingView的显示
  • Adapter负责映射Message Presenters 和ViewHolder
  • message的 Presenter 负责单条消息的逻辑
  • ViewHolder 负责单条消息的显示

所有的组成元素都是低耦合的,非常容易单独测试。
并且,当你有一个界面展现消息列表,一个界面展示消息详情,那么你可以重用相同的Presenter,只要实现两个不同的View接口(一个是VIewHolder,一个是Fragment)。同样的,View的接口可以被自定义view实现,这样可以重用自定义控件。

MVP 和配置改变

如果你开发过Android App,那么你应该在知道支持设备旋转和配置改变是一件痛苦的事情:

  • 每次在使用Activity或者Fragment时,就必须考虑,如果设备旋转,应该怎么处理,是否需要保存什么数据。
  • 在后台线程处理长时间任务时,最容易犯的错误就是持有Activity或者是Fragment的引用,必须要等到任务结束时才能释放,这样有可能会导致内存泄露。

使用MVP可以正确的处理这一切而你不需要考虑它,因为Presenter 对象没有持有UI强引用,它们都是轻量级的并且可以在方向改变时保留实例。因为Presenter 持有了Model的引用和View的状态,在配置文件改变时,它能重新创建。
下面是假设用户下载时,方向旋转手机屏幕,MVP怎样工作:

  1. Activity第一次被创建,会创建新的Presenter,绑定到当前Activity。
  2. 点击下载按钮,长时间任务开始在Presenter中运行。
  3. 旋转屏幕,Presenter和Activity解绑,第一个Activity实例被回收,Presenter实例仍然保留,下载任务仍然运行。
  4. 第二个Activity实例被创建,绑定原来的Presenter。
  5. 下载任务完成,Presenter更新View。

更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. android io写入读取 txt 数据 封装
  3. eclipse导入android项目后出现错误的解决方法
  4. 初学Android,短信管理器之发送短信(六十五)
  5. android 访问WebService
  6. android 获取正在运行的后台service的代码
  7. Android友盟推送接入
  8. Android(安卓)Databinding 与 RecyclerView 完美结合
  9. Android自学笔记-10-Sqlite的简单使用

随机推荐

  1. Android(安卓)Support Package
  2. Eclipse Android(安卓)代码自动提示功能
  3. Android(安卓)- 干货收集。
  4. android:cacheColorHint,android:listSel
  5. Android与PC通过USB连接通信(一)
  6. [转」android中的数据库操作
  7. Android四种Activity的加载模式
  8. Android(安卓)中文 API (34) ―― RadioGro
  9. Android联系人数据库全解析(1)
  10. android里面EditTex多行输入及输入置顶问