Guide to app architecture 1 - 2022版翻译

如何构建高质量并稳如狗的APP?该指南包含了你想要的的最佳实践方案和官方推荐的架构。

注:该指南假定你已经熟悉Android Framework,如果是新手,请学习课程Android Basics course,你会学一些该指南中提到的概念和知识。

移动APP的用户体验

一个典型的Android APP会用到以下组件:activity, fragment, service, content provider, broadcast receivers,大部分会在menifest文件中声明。Android OS使用该文件把应用和用户交互整合起来。一个设备上有多个app,一个app有多个组件,用户在玩手机,短时间内他会在几个app间来回切换,比如在音乐APP听歌,老板来电话了,就切换到电话APP接听,老板让发一份材料到邮箱,挂断以后就切换到邮件APP发邮件,打开文件管理APP选了需要的文件,把邮件发送出去后重新切换回音乐APP听音乐,这一系列操作背后都隐藏了不同类型的用户驱动的工作流程和任务。试想一下音乐APP是你开发的,如何设计来适配这些流程和任务?

移动设备资源有限,系统可能会在任何时刻杀掉某些APP进程来为新启动的进程腾出空间。

在这种条件下,你的APP组件可能是单独并随机无序的启动的,OS或用户可能随时关掉它。这种随机性事件是你无法控制的,所以不应该在组件中保存应用数据或状态,且组件间不应相互依赖。

常见的架构原则

如果不应该使用组件来保存应用数据和状态,那应该怎么设计APP呢?

随着android应用的规模不断扩大,对应用就有一定的要求了,能够方便的扩展,保证稳健性,保证易于测试,这些要求意味着需要一个好的架构。

APP架构会定义:1.应用程序中有几个part, 2.part的边界,3.part承担的职责。要满足这些需求,架构要遵循一些特定的原则。

Separation of concerns关注点分离原则

SOC
对只与“特定概念、目标”(关注点)相关联的软件组成部分进行“标识、封装和操纵”的能力,即标识、封装和操纵关注点的能力。
这是处理复杂性的一个原则,由于关注点混杂在一起会导致复杂性增加,所以要把不同的关注点分离开来,分别处理。
好处:
“系统中的一个部分发生了变化,不会影响其他部分。”
“即使需要改变,也能够清晰地识别出那些部分需要改变。”
“如果需要扩展架构,将影响最小化,已经可以工作的每个部分都将继续工作。”

常见的错误是把所有的代码都写在activity或者fragment中。这些基于 UI 的类应该只包含处理 UI 和操作系统交互的逻辑。精简这些类,能避免许多与组件生命周期相关的问题,并提高这些类的可测试性。

Activity和Fragment的实现是android系统负责的,你并没有负责其实现,它们只是一个胶水类,用来粘合你写的APP和Android系统,这种粘合性的体现就是APP和系统之间的契约。系统在某些状况下会杀掉APP。例如用户交互时主动关掉APP,或者设备电量不足时系统杀掉APP。为了提供令人满意的用户体验和更易于管理的应用程序维护体验,最好尽量减少对它们的依赖。

Drive UI from data models(数据模型驱动UI)

另一个重要原则是用数据模型驱动UI,最好是持久化模型。数据模型决定了展现在APP上的数据。数据模型独立于APP的UI元素和其他组件,这也意味着数据模型和UI&组件的生命周期无关。但是当OS从内存中删除应用进程的时候,它们仍然会消失。

使用持久化模型会很爽,原因如下:

  • 当Android系统杀掉APP的时候,用数据不会丢失。
  • 当网络连接很弱,或者不可用的时候,APP可以继续运行。

如果App架构基于数据模型,App就会更健壮,更加方便测试。

推荐的应用架构

本节演示如何按照推荐的最佳实践来构建你的应用。

注意:这里的建议和最佳实践可广泛的应用于APP架构,方便扩展、提高APP质量和稳健性,并使之易于测试。但是,这只是一个指南,要根据需要进行调整以适应您的要求。

根据上面提到的架构原则,每个应用程序至少要有两层:

  1. UI层:把数据展现在屏幕上
  2. 数据层:处理业务逻辑;提供数据

可以另外的层,如domain层,用来简化和重用UI层和DATA层之间的交互。
Guide to app architecture 1 - 2022版翻译_第1张图片

注:图中的箭头表示类之间的依赖。domain layer依赖 data layer。

UI Layer

该层的职责是展示应用数据到屏幕上。当数据发生变化时,要把这些变化展现在屏幕上。数据变化来自用户交互(如点击按钮)或者外部输入(如network response)。

UI层由两部分组成:

  1. UI elements: 把数据渲染到屏幕上,使用各种View或者Jetpack Compose来构建elements.
  2. State holders: 例如ViewModel类,用来持有数据并把数据提供给UI,并且负责逻辑处理。

于是上图扩展为:
Guide to app architecture 1 - 2022版翻译_第2张图片

Data Layer

该层包含业务逻辑,业务逻辑由一系列规则组成,决定了APP如何创建,存储并更改数据,这会赋予APP价值。
该层由repositories组成,每一个repository都包含0到多个数据源。对每个不同的数据类型都要创建一个repository类。例如,对于movie相关的数据要创建一个MoviesRepository类,对于payments相关的数据要创建一个PaymentsRepository。
Guide to app architecture 1 - 2022版翻译_第3张图片
Repository类主要负责下列任务:

  1. 为应用的其他部分提供数据
  2. 集中处理数据更新
  3. 协调多数据源
  4. 从应用的其他部分冲向数据源
  5. 处理业务逻辑

每个数据源类只负责处理一个数据源,可以是文件数据源,网络数据源,本地DB数据源。数据源类是application和system之间操作数据的桥梁。

Domain Layer

该层是可选的,位于UI Layer 和 Data Layer之间。用于封装复杂的业务逻辑或者简单的被多个ViewModel复用的简单业务逻辑。因为并不是所有的APP都有这些需求,所以它是可选的。在需要的时候才用到,例如处理复杂性和可复用性。
Guide to app architecture 1 - 2022版翻译_第4张图片

这一层的类通常称为use cases / interactors. 每个use case负责一个单一的功能。例如有好几个ViewModel都要依赖时区信息在屏幕上展示信息,那么就可以设计一个GetTimeZoneCase类来专门负责。

处理各组件之间的依赖

APP中的类需要其他类才能正确的运行。可以使用下面任意一种设计模式来收集相关类的依赖:

  • DI:依赖注入允许类在不构造它们的情况下定义它们的依赖关系。在运行时,由另一个类负责这些依赖项。
  • Service Locator: 服务定位器模式为类提供了一个注册表,可以在其中获取类的依赖而不是构造它们。

这些模式允许你方便的扩展代码,因为它们提供了清晰的模式用于管理类之间的依赖,去掉了重复代码,避免掉了复杂性。另外这些模式还有助于在测试和生产环境中快速切换。

通用的最佳实践

编程是一个创造性的领域,构建Android应用也不例外。对于一个问题可以有很多中解决方案;你可能会在多个activity和fragment中传递数据;为了离线模式,可能从远程获取数据并将其持久化在本地;或处理其他常见的场景。
虽然下面的建议不是强制性的,但是在多数情况下,从长远角度来看,遵循这些建议会使得代码库更加强健,易于测试和维护。
不要在组件中存储数据
避免将APP的entry point(如activity,service,broadcast receiver)指定为数据源。相反,entry point应只和其他组件协调来获取该entry point相关的数据子集。组件的生命周期都取决于用户和设备的交互,以及系统当前的状况,它们的生命周期都很短。
减少android类的依赖
你的应用组件应该是唯一依赖android framework sdk api的类,将应用中的其他类从中抽象出来有助于提高可测试性,并减少耦合度。
在应用程序的各个模块之间创建明确定义的职责边界
例如,不要将从网络加载数据的代码分散到代码库中的多个类或包中。同样,不要在同一个类中定义多个不相关的职责——例如数据缓存和数据绑定。遵循该指南有助于解决此问题。
每个模块不要暴露太多
例如,对与一个模块,不要试图向外暴露内部实现细节。可能在短期内很爽,时间长了代码就会越来越乱。
关注自己APP的核心是指在众多APP中脱颖而出
不要编写相同的样板代码来重新发明轮子。相反,将时间和精力集中在使您的APP与众不同的地方,并让 Jetpack 库和其他推荐的库来处理重复的样板文件。
考虑如何使您的应用程序的每个部分都可单独测试
例如,如果有一个从网络获取数据的定义明确的 API ,那么久可以更轻松地测试将数据保存在本地数据库中的模块。相反,如果您将这两个模块的逻辑混合在一起,或者将网络代码分布在整个代码库中,那么有效测试会变得更加困难。
尽可能多地保留相关的最新数据
这样,即使设备处于离线模式,用户也可以使用您的应用程序的功能。请记住,并非所有用户都有持续的高网速——即使他们有,在有的地方网速也不会高。

Samples
下面这些例子是Google官方例子,按照该指南进行设计。

你可能感兴趣的:(Guide to app architecture 1 - 2022版翻译)