作者: madroid
回顾
根据 App 行为的不同,我们对其进行分离/分层并确定其职责,每层之间的通讯交互采用响应式方式。
App 有三层结构,分别为 UI Layer、Domain Layer、Data Layer,其依赖关系是单向的,上层可以依赖下层,下层却不能反过来依赖上层。大致如下,其中 Domain Layer 是可选层:
每层的主要职责分别为:
1、UI Layer: 使用 UI 元素展示 App 中数据
-
- 将底层数据处理成容易被 UI elements 使用的 UiState 数据;
- 根据 UiState 绘制对应的 UI elements;
- 响应用户的操作事件,根据需求对其进行分发;
2、Domain Layer: 封装通用的业务逻辑
-
- 封装复杂的业务逻辑,避免出现大型类;
- 封装多 ViewModel 通用的业务逻辑,避免代码重复;
3、Data Layer: 封装统一的数据来源,提供单一可信来源
-
- 定义不同的 DataSource 来封装 Framework 及三方 SDK 的 API;
- 定义 Repository 来整合相同业务的不同数据类型的 DataSource;
每层依赖关系是单向的,UI Layer 可以依赖 Domain Layer,但是 Domain Layer 却不能依赖 UI Layer。这种依赖方式可以使用简单的函数传递依赖事件,但是却不能处理结果的回调,即 UiState 的更新。想要处理结果的回调每层之间就可以采用数据驱动/响应式的方式来交互了。这种方式也被称为是单向数据流的方式,即 UI 事件从 UI 层流向数据层,UiState 从数据层流向 UI 层。
关于 UI Layer、Domain Layer、Data Layer 中更多详细内容可以查看官方文档应用架构指南:
https://developer.android.google.cn/jetpack/guide
与 MVI 的关系?
MVI 的全称是 Model-View-Intent,这里的 Intent 并不是指 Android 中的 Intent 类,而是表示一种意图,可以简单理解为对用户 Event 的一种抽象。其交互图大致如下:
MVI 并不像 MVC、MVP、MVVM 一样,不论是 Controller、Presenter 还是 ViewModel 都是 View 与 Model 之间的桥接类,负责这两者之间的通信与交互 (虽然 MVC 可以跨过 Controller 直接进行交互)。而 Intent 并没有类似的职责,仅仅是约束了 View 的事件通过类似枚举的方式定义,这种方式更像是前端框架中的 Flux 或者是 Redux,更多内容可以查看 Reclaim the reactivity of your state management, say no to imperative MVI,实现 MVI 的主流框架有: Orbit、Mavericks、Uniflow-kt、Mobius。
- Reclaim the reactivity of your state management, say no to imperative MVI
https://zhuinden.medium.com/reclaim-the-reactivity-of-your-state-management-say-no-to-imperative-mvi-3b23ca6b8537
- Orbit
https://github.com/orbit-mvi/orbit-mvi/blob/06e9f759a87e7192767baeebc682fc92369a7eff/orbit-core/src/commonMain/kotlin/org/orbitmvi/orbit/internal/RealContainer.kt#L74-L75
- Mavericks
https://github.com/airbnb/mavericks/blob/e8a631a19fc1b044da3ddff358712e129dc487a6/mvrx/src/main/kotlin/com/airbnb/mvrx/CoroutinesStateStore.kt#L57-L59
- Uniflow-kt
https://github.com/uniflow-kt/uniflow-kt/blob/a1fdbeb733a0b550a162227be3b1e03d03197023/uniflow-core/src/main/kotlin/io/uniflow/core/flow/ActionReducer.kt#L28-L32
- Mobius
https://github.com/spotify/mobius
有的 MVI 在实现还需要借助 ViewModel,仅仅是把 View 的事件定义成的对应的密封类。目的仅仅是为了强制实现单向数据流的方式,根据之前介绍实现单向数据流的方式还是比较简单的,上层只能依赖下层实现,下层的处理结果通过 LiveData、Flow 方式更新。