Android 中的框架模式

职责划分的问题。一个 Android UI 应用的职责到底有哪些?

想象一个好友页,需要展示用户的基本信息,还有提供两个按钮分别对话和删除或添加按钮(需要更加用户是否是好友来判断)。实现这个页需要的职责有:

  1. 将设计稿转换为手机上的界面元素。比如写 layout 文件
  2. 响应用户事件,比如按钮被按下
  3. 将用户信息填入界面,甚至更改界面元素的关系,比如显示添加或者删除按钮。
  4. 实现对话、删除、添加按钮该做什么
  5. 获取用户信息,一般来说是个异步耗时操作
  6. 界面需要反映正在读取中这个操作
  7. 需对错误进行处理
  8. 需要对 Android 的生命周期进行处理。

MVC

  • View:先对是最简单的 View,相当于 layout 文件,尽量保持『愚蠢』(dump),基本就是单纯的布局界面元素
  • Controller: Acitvity,部分更改 View 的功能,和业务逻辑。
  • Model:数据模型,数据来源,持久化

对于 MVC 来说,View 是最简单只负责第一个职责。Controller 相当于 Activity,需要做的事情就多了,需要读取用户信息,读取过程中需要启动一个 ProgressBar 来告知用户正在读取中。还要为按钮添加监听器。每个按钮的本地业务逻辑也会放在这里。读取完成后,将信息填入各个 View 里,控制第二个按钮是显示添加还是删除。还可能读取失败就需要显示一个 Toast 告知。还有处理个各个生命周期回调,比如 onDestroy 的时候关闭与数据源的连接等等。

Model 层,包括数据对象,和数据源继续交互,比如获取数据,更改数据。比如添加好友,可能就需要添加好友 API,这也是一个异步操作。

如上图,Model 的更新需要通知 View,但 Android 中并没做到这一点。

MVP

  • View: layout 和 Activity
  • Presenter:响应 View 的事件,通知 View 更新,通知 Model 修改,接收 Model 改变的通知
  • Model:

对于 MVP,View 多了 Activity,做的事情相对多了一些。layout 负责布局,Activity 也算是一个 Controller,只是变得简单了,不再主动控制读取数据。而是定义一个 UserView 接口用于隔离 View 和 Presenter。比如,

  • setUser
  • showLoading
  • showContent
  • showError

这样就把 Activity 和 Presenter 隔离开了,Persenter 负责读取数据,告知 View 显示读取中,至于怎么显示,是弹出 ProgressBarDialog 还是在页面内转菊花,Presenter 就不管了。Presenter 不保存 Activity 的引用,只是保存 UserView 接口。而 Activity 则需要保存 Presenter,一旦发生用户事件,Activity 需要通知 Presenter 进行处理(实际上还有系统事件也要 Presenter 处理。),比如说

mConversationButton.click(()->{mPresenter.onConversationButtonClick()});

第二个按钮情况就有点复杂了,它根据用户状态的不同,涉及不同的业务逻辑。是不是该在 Activity 中写:

mAddOrDelButton.click(()->{user.isFriend?mPresenter.onDelButtonClick():mPresenter.onAddButtonClick()});

实际上这就涉及 View 的厚度问题,简单的逻辑放入 View 中无可厚非,不过 Passive View 来说,还是放在 Pensenter 合理写。

mAddOrDelButton.click(()->{mPresenter.mAddOrDelButtonClick()});

View 层要保持简单,保存愚蠢,所谓的 Passive View,涉及的业务逻辑的东西就应该放入 Presenter,Presenter 负责做各种脏活。

MVP purists would argue that the presenter should never have any references to any Android APIs or code. MVP 中 Activity 只是作为 dump view 的一部分。MVP 中也有 Controller, Controller is the component that handles the click events and calls the corresponding Presenter methods.所以把他归入 View 层。

MVP – Mosby

对 Presenter 来说 View 是一个接口,mocking 更容易

MVVM

  • View: layout 和 Activity
  • ViewModel:两个职责,传递用户动作;更新 View。

MVVM is attractive for platforms which support bi-directional binding with less effort.

利用数据双向绑定功能,让 Presenter 变薄,只起到一个同步 View 和 Model 中介的角色,所以便叫 ViewModel。

ViewModel 不像 Presenter 拥有 View 的引用,不依赖于 View

https://github.com/inloop/AndroidViewModel

MVVM on Android: What You Need to Know

注解减少代码量

- sockeqwe/fragmentargs: Annotation Processor for setting arguments in android fragments

https://nirajrules.wordpress.com/2009/07/18/mvc-vs-mvp-vs-mvvm/

Medium

其他

类图

类图的危险,在于专注于类的结构而忽略行为

 ---------
|  Name   |
 ---------
|  Props  |
 ---------
|   Ops   |
 ---------

属性(Properties)

属性语法:visibility name: type multiplicity = default {property-string},例子:- name: String [1] = "Untitled" {readOnly}

操作(Operations)

操作是类知道要执行的动作。visibility name (parameter-list) : return-type {property-string} ,比如:+ balanceOn (date: Date) : Money

不更改系统状态的操作称为 query,更改系统状态的操作称为 modifier

关系

关联(Association)

实线带箭头,由源类指向目标类。属性其实也是一种关联关系。虽然两种表示法都差不多,但关联关系,能在关系的两边都表示多重性(multiplicities)。

一般来说用原生类型或者一些简单的类型用属性表示,重要的类型用关联关系表示。

双向关联(bidirectional association)

实现两端带箭头:

泛化(Generaliztation)

超类是子类的泛化。见 广义化 - 维基百科,自由的百科全书

泛化是传递的。

分类(Classification)

实例化

依赖(Dependency)

如果一个关系中,B 的更改会导致 A 的更改,那么称为 A 依赖 B,比如 B 更改了 A 调用的方法名。

依赖关系不是传递的,比如 B 依赖 C,当 A 不一定依赖 C,

聚合与组合(Aggregation and Composition)

多重性(Multiplicity)

Multiplicity:由两个值组成:n..m,如果 n = m,可以简化为 n。另外 0..* 可以简化为 *

  • 可选:0.
  • 必须:低位值不为 0
  • 单值:1.
  • 多值:高位值不为 1,一般为 *

可见性(Visibility)

visibility: + (public), – (private), ~ (package), and # (protected).

用例图

Java 8

Android Studio 2.4 支持 Java 8 ,

对于 lambda 表达式,方法引用,等等语法改进支持到任意平台,其他 java 8 API 支持 API 24 以上支持。

与 retrolambda 最大的区别是,Android Studio 是在 .class 文件上做出来。通过一个工具 desugar。而 retrolambda 是在源码上做处理,不能支持一些用 java 8 特性编译后的库。

Use Java 8 language features | Android Studio