Android 现代 App 架构 - 启程(一)

2021 年底,Android 官方发博文[1]称对之前的架构指南做了一次重大改版,整体上将 App 分为 3 大部分:UI LayerDomain LayerData Layer。本文就是解读此次改版的方方面面的第一篇文章,期望是通过这一系列文章带你快速掌 Android 握新版架构的核心要领。

好的,下面直接进入正文。首先看下为什么 App 需要架构设计?

面对的挑战

随着 App 功能的不断增加,其代码实现复杂度将会呈指数级增加,具体体现在以下几个方面:

  1. 允许 App 的功能要能顾灵活的扩展与收缩;

  2. 保证 App 的稳定性与健壮性;

  3. 使 App 容易测试;

所以在 App 开发的过程中必须要有一个合适的架构指南来帮助完成上述挑战。

架构指南

为了满足上面的一些需求,整体架构至少需要采用以下几个大的设计原则:

📌 分离关注点[2]

分离关注点是解决复杂问题的一种常见的解决方案,它是将一个计算机程序拆分为不同部分的设计原则。每一部分都有自己需要关注的焦点。从而达到将一个复杂问题拆解成多个简单问题的效果。

如 ActivityFragment 主要职责是绘制数据与响应用户的操作事件;于此同时,Android 系统可以根据当前系统的资源状况随时对其进行销毁。如果想要在此部分中编写业务逻辑以及耗时操作的话,将会增加其复杂度,从而导致页面开发变得难于维护(容易产生 bug)。

关注分离点这种解决问题的思路并非仅适用于计算机编程问题,比如阿德勒心理学中的客体分离概念也与此大同小异。

📌 数据驱动页面

数据是项目的核心,也是状态的最终保存者。而视图,只不过是一种能够由数据延迟计算出来的最终结果而已,它本身不存储状态。

这也是近些年响应式编程的流向的原因之一,将更多的精力放在的复杂数据的处理上,View 只需要观察数据变化并做出响应即可。

除了上面的指导原则之外,还有一个官方文档中没有提到的一些设计准则仍然非常有用:

  • KISS[3]:同一问题的不同解决方案中,应选择简单的那个方案;

  • SOLID[4]:面向对象编程的一些基本原则;

  • 更多[5]对开发人员有用的定律、理论、原则和模式;

推荐架构

根据以上的架构指南,一个 App 至少应该拆分为两层,UI 层及数据层:

  • UI Layer - 在屏幕上显示应用数据。

  • Data Layer - 包含应用的业务逻辑并公开应用数据。

还可以额外添加一个 Domain 层,以重用界面层的业务逻辑或是拆分业务避免大型类。整体如下:

图片

App Arch Layer Design

UI Layer[6]

UI Layer 主要包含了以下几个部分:

  • View Container:View 的容器,是 View 渲染的入口,一般是指 Activity、Fragment;

  • UI elements:UI 元素,是用来渲染界面的,可以是 Views 也可以是 Compose 函数;

  • States holders:UiState 的持有者,是最终组装 UiState 的地方,一般是 ViewModel 类;

  • event:用户的交互事件,通常需要在产生、更新数据,代理给 ViewModel 处理;

  • UiState:UI 的状态数据,用来渲染 UI elements 的数据,通过观察者方式提高;

UI Layer Design

UI Layer 主要是做了一下几件事情:

  • 将 App 中的数据转换成容易被 UI Elements 渲染的数据(UiState)。这部分转换主要发生在 State Holder 中。

  • 将 UiState 转换为对应的 UI elements 展示给用户。这部分主要发生在 Activity 或 Fragment 中,不论 Activity 和 Fragment 使用的是 View 还是  Jetpack Compose[7]  构建的。

  • 接收 UI elements 中的输入事件,并且根据需要做出响应。

Domain Layer[8]

Domain Layer 主要是可以做以下两件事情:

  • 封装复杂的业务逻辑,避免出现大型类

  • 封装多 ViewModel 通用的业务逻辑,避免代码重复

Domain Layer 是一个可选层,可以根据自己项目的复杂情况决定是否使用。Domain Layer 主要是有不同的 UseCase(有的框架中也称作 Interactor)组成,其依赖关系大致如下:

Domain Layer

Data Layer[9]

Data Layer 主要做了下面两件事情:

  • 通过 DataSource 封装系统及三方 API;

  • 通过 Repository 使用 DataSource 封装业务逻辑,并暴露给使用者;

一个业务模块中可以包含一个或者多个 Repository ,每个 Repository 中包含零个或多个 DataSourceDataSource 根据其来源可以分为 LocalDataSourceRemoteDataSource 等。大致依赖关系如下:

Data Layer

依赖管理

以上几层内容中会存在大量类的初始化及注入管理问题,如果处理不好将会导致一些不必要的麻烦。这种问题有两种解决方案:

  1. 依赖注入[10]:依赖注入使类能够定义其依赖项而不构造它们。在运行时,另一个类负责提供这些依赖项。一般是使用注解方式,适合大中型项目,如 Hilt[11];

  2. 服务查找[12]:服务查找的方式一般是维护一个注册表,所需的依赖都可以在这个注册表中查找;一般是使用相对简单,适合中小型项目,如 koin[13];

官方推荐使用 Hilt 来进行依赖管理,如果你的项目中在使用其他的依赖管理方式,并且没有遇到问题的话,那么继续使用当前的框架即可。

当然还是会有一些其他的最佳实践需要我们去遵守:

最佳实践

  1. 不要将数据在 Android 四大组件中处理,他们有自己的生命周期我们很难控制;

  2. 尽量减少对 Android 类(ContextActivity等)的依赖,减少耦合,提高可测试性;

  3. 需要明确各个模块中的职责,在各自的分层中仅做自己职责范围内的事情,减少耦合;

  4. 每个模块仅仅只需暴露自己应该提供的功能,保持越简单越好;

  5. 应尽量设计离线模式,用户在网络不可用的情况下,仍然可以使用 App;

感谢你的阅读,下一篇将会解读 UI Layer 中的一些具体内容。

参考资料

[1]

发博文: https://android-developers.googleblog.com/2021/12/rebuilding-our-guide-to-app-architecture.html

[2]

分离关注点: https://en.wikipedia.org/wiki/Separation_of_concerns

[3]

KISS: https://zh.wikipedia.org/wiki/KISS%E5%8E%9F%E5%88%99

[4]

SOLID: https://en.wikipedia.org/wiki/SOLID

[5]

更多: https://github.com/dwmkerr/hacker-laws

[6]

UI Layer: https://developer.android.com/jetpack/guide/data-layer

[7]

Jetpack Compose: https://developer.android.com/jetpack/compose

[8]

Domain Layer: https://developer.android.com/jetpack/guide/domain-layer

[9]

Data Layer: https://developer.android.com/jetpack/guide/data-layer

[10]

依赖注入: https://developer.android.com/training/dependency-injection

[11]

Hilt: https://developer.android.com/training/dependency-injection/hilt-android

[12]

服务查找: https://en.wikipedia.org/wiki/Service_locator_pattern

[13]

koin: https://github.com/InsertKoinIO/koin

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值