Activity, BroadcastReceiver, Ser

2017-06-27  本文已影响23人  zac4j

译自: DianneHackborn Post

“我该如何设计我的 Android 应用?我该使用哪种 MVC 模式?我该用 event bus 做些什么?”

TL;DR :)

我们经常会看到 Android 平台的工程师询问该如何在他们 app 中使用设计模式和架构设计。答案也许是令人惊讶的,我们往往并没有强烈的意愿或者真知灼见。

(这里的我们是指 Android Platform 开发小组,并不是指 Goolge 或 Android 开发者。在 Google 内部或外部有很多关于如何编写 app 的优秀的意见和建议,我不打算去反驳这些。)

你是否该使用 MVC ? 或 MVP ? 或 MVVM ?
这个我不知道。我在学校里了解过 MVC,其他的(MVP/MVVM)是 Google 搜索后才写到前面的。这可能有点让人惊讶,因为 Android 感觉像是有强烈的意见指引该如何去写 app —— 通过其 Java API 以及一些高级的概念,它可能看起来像一个典型的应用框架,指导 app 应该如何工作,但绝大多数情况下并不是这样。

将核心 Android API 称为“系统框架”可能会更好。在大多数情况下,我们提供的平台 API 用于定义 app 和操作系统的交互方式;但对于存在于 app 中的任何内容,这些 API 通常与之无关。也就是说,Android API 通常看起来与期望的操作系统 API 不同(或更高级),从而导致该如何使用它们显得比较迷惑。
举例来说,来看看操作系统定义“如何启动一个 app”。在一个经典的系统中,app 像这样启动:

int main(...) {
  // My app goes here!
}

操作系统启动 app,调用它的 main() 方法,app 运行并执行所需的操作,直到它决定完成。这里没有任何关于 app 需要怎么做以及该如何设计 main() 方法里的操作——这是个纯净的白板。
然而在 Android 中,我们明确的决定不会有一个 main() 方法,因为我们需要让平台更好地控制 app 的运行方式。特别是,我们需要设计一个用户无需考虑开始以及停止 app 的系统,由系统为他们完成这部分工作...所以系统需要有更多的关于每个 app 内部发生的情况的信息,并且能够在需要时以各种有效的方式启动 app,即使它们当前没有运行。
为了做到这一点,我们将 app 典型的主要入口分解成系统可以使用的几种不同的交互。它们是 Activity, BroadcastReceiver,ServiceContentProvider API,Android 开发者可以迅速熟悉它们。
为了说明,让我们简单的看看这些不同的 API以及他们对 Android 系统的意义。

Activity

这是 app 与用户交互的入口。从系统的角度,它与 app 提供的关键交互是:

我们没有关注的地方:
当我们进入你的 UI 入口后,我们不需要关注如何组织内部的流程。使用单一的 Activity 更改它的 views,或者使用 fragment 和其他框架,或者将其分解为额外的 activities。或者根据需求以上三条都做,只要你保持和 Activity 的上层做连接(它在适当的状态下启动,保存/恢复当前的状态),这和系统没有关系。

BroadcastReceiver

这是系统将事件传递到普通用户流之外的应用程序的机制。最重要的是,因为这是另一个明确定义的 app 入口,系统可以传递 broadcast 到 app 即使它当前不在运行。举例来说,app 可以安排闹钟来发布通知,告诉用户待办事件...通过将该闹钟的 broadcast 传递到 app 内的 BroadcastReceiver,无需该应用保持运行直到闹钟关闭。

我们没有关注的地方:
App 内的 event 调度是一件完全不同的事,是否你使用一些 event bus 框架,实现你自己的回调系统,以及其他...并没有理由使用系统的广播机制,因为你没有跨app 调度 event(实际上有很多理由不这样做——在 app 的内部实现使用全局的广播机制会有很多不必要的开销和许多潜在的安全问题。)我们确实提供了 LocalBroadcastManager 类,它实现了纯进程内 intent 调度系统,与系统API具有相似的 API,如果你碰巧喜欢它们:)。但是,没有其他理由在你的 app 中使用系统的广播机制。

Service

一个由于各种原因需要保持 app 在后台运行的通用的入口。实际上有两条非常独特语义的 service 告诉系统如何管理应用程序:

Start service 告诉系统,由于某些原因,“让我保持运行,直到我说完成了。”这可以用来同步一些数据,或者在用户离开 app 后播放音乐。这也代表了两种不用类型的 start service,描绘系统该如何处理它们:

Bound service 正在运行,因为其他 app (或系统)表示要使用该服务。这基本上是为另一个进程提供 API 的服务。系统知道这些进程之间存在依赖关系,因此如果进程 A 与进程B中的服务绑定,系统需要保持进程 B(以及它的 service)以运行 A。此外,如果进程 A 是用户所关注的,系统同样会关注进程 B。
由于其灵活性(好的或坏的),service 已被证明是各种上层系统概念的非常有用的构建基础。动态壁纸,通知监听器,屏保程序,输入程序,服务功能服务,以及许多其他核心系统功能都以 service 构建应用实现,当它们需要运行时与系统的 service 绑定。

我们没有关注的地方:
Android 不会关心你的 app 内管理使用流程的操作,因此这种场景没有必要使用 service。例如,你想为 UI 开启后台下载任务,为此你不应该使用 service —— 实际上不必告诉系统你的进程需要持续运行,因为它真的不需要。
如果你创建一个简单的后台线程(或者任意非 service 机制)下载东西,你将获得潜在的场景:当用户处在 app 的 UI 界面,系统将保持你的 app 进程,下载任务不会被打断。当用户离开 UI 界面,只要其他地方不需要 RAM,你的进程将被保留(缓存)并将能够持续下载。
同样,对于连接同一 app 内的不同模块,没有理由在同一进程中使用 bind service,这样做并不十分有害——系统发现进程依赖于自身,因此不必做比寻常更多的事情,但对于 app 和系统来说却做了许多无用功。此外,你应该使用单例或者其他的进程内模式连接 app 内的不同模块。

ContentProvider

ContentProvider 是一个专业的 app 数据 publish 工具。人们通常认为它是数据库层的抽象,因为它有很多与数据库相关的支持和 API ...然而从系统设计的角度,并不像那样。
ContentProvider 是 app 发布数据条目的入口,通过 URI scheme 标识。因此,app 可以决定如何将其包含的数据映射到 URI 命名空间,将这些 URI 发给可以依此访问数据的其他 entities。系统在管理 app 时可以使用一些特殊的操作:

我们没有关注的地方:
如何实现 content provider 背后的数据管理并不重要;如果你不需要SQLite 数据库中的结构化数据,不必使用 SQLite。例如,FileProvider helper class 是通过 content provider 使你 app 内 raw 文件可用的简单方法。
同样,如果你没有从 app 发布数据供其它人使用,则完全没必要使用 content provider。因为围绕 content provider 构建的各种 helper class 可以便捷地将数据放入 SQLite 并将其用于填充 UI 组件(如 ListView)。但假如这些工具使你开发更加困难,说明你不需要使用它,而应该为你的 app 训责

上一篇 下一篇

猜你喜欢

热点阅读