1. 状态共享架构全景:领域分层、平台边界、跨模块依赖、统一数据源设计
在 KMP + Compose 项目中,状态共享不仅仅是“多个界面读取同一变量”,而是涉及领域模型隔离、平台能力桥接、模块间依赖控制、数据源单一事实来源四个核心维度的系统设计。本节从架构顶层绘制全景,为后续章节的每一层拆解提供坐标系。
1.1 四层核心职责矩阵
| 架构层 | 职责 | 平台边界 | 共享范围 |
|---|---|---|---|
| UI / Compose | 纯展示、用户事件映射、Compose 生命周期绑定 | Android / iOS 各自宿主 Activity/ViewController | 不可共享(只同平台) |
| Domain(领域层) | 业务逻辑、用例编排、状态转换规则 | 纯 Kotlin,无平台 API 依赖 | 所有模块共用 |
| Data(数据层) | 数据存储、网络请求、缓存、同步策略 | KMP 对应平台实现(expect/actual) | 模块间隔离,通过统一接口访问 |
| 平台桥接层 | 传感器、文件系统、推送等原生能力适配 | Android / iOS 各自 actual 实现 | 仅对 Domain 暴露抽象接口 |
每层之间有严格的单向依赖:UI → Domain → Data → Platform。任何反向依赖(例如 Domain 直接依赖 UI)都会破坏架构的可测试性和复用性。
1.2 统一数据源设计原则
为了避免“多处写、读不一致”,统一数据源要求所有状态变更都通过唯一的仓储(Repository)入口,且 Domain 层只感知抽象的 Flow<T> 或 StateFlow<T>。实现策略包括:
- 本地优先:写操作先写入本地数据库(如 SQLDelight),再异步同步到远端。
- 跨模块引用:通过 Gradle 模块依赖声明
api或implementation,避免循环依赖。 - 状态收敛:一个业务实体只由一个 Repository 管理,不允许不同模块缓存同实体的两份副本。
关键认知:统一数据源不是强制所有数据放在同一个数据库,而是保证“任何一条数据只有一个权威写入路径”。
1.3 状态共享架构全景图
下图展示了 KMP 项目中状态共享涉及的领域分层、平台边界、模块依赖和数据流方向。节点颜色对应架构层,箭头代表数据流与控制流方向。
1.4 数据流与控制流分解
状态共享中的信任链路遵循“向下依赖接口,向上推送事件”:
- 数据流:Data 层通过
Flow向上发送状态快照 → Domain 层做去重、合并、业务转换 → UI 层通过collectAsState()驱动重组。 - 控制流:用户操作 → ViewModel 调用 Domain UseCase → UseCase 调用 Repository → Repository 决定写本地还是远端。
- 信任链路:UI 信任 Domain 返回的状态是正确且唯一的;Domain 信任 Data 层的 Repository 是统一入口;Data 层信任平台桥接提供的原生能力符合预期。
1.5 选型权衡与风险点
| 关注点 | 选型建议 | 风险 |
|---|---|---|
| 状态容器 | StateFlow + MutableStateFlow(Compose 原生支持) | 初学容易混用 LiveData 或 RxJava,增加平台耦合 |
| 跨模块依赖 | Gradle 模块分离 + api/implementation 管控 |
如果没有 dependency guard,容易产生循环依赖或版本冲突 |
| 数据同步一致性 | 本地优先 + 乐观更新 + 冲突解决策略 | 网络离线时 UI 显示过期数据,用户感知不一致 |
| 平台桥接层 | 使用 expect/actual 声明,Domain 层只依赖接口 | expect/actual 无法跨模块共用,需放到 commonMain 的同名包下 |
避坑提示:不要为了“共享”而将所有状态提升到 Domain 层。只有业务相关的、需要跨平台复用的状态才放在 Domain;纯 UI 状态(如动画参数、列表滚动位移)应保留在 UI 层以保持 就近原则。
1.6 落地步骤(参考)
- 划分模块边界:创建
:shared、:data、:domain、:ui四个 Gradle 模块,在settings.gradle.kts中声明依赖关系。 - 定义统一数据源接口:在
:data模块中定义UserRepository接口及其expect声明。 - 实现平台 actual:在
:androidApp和:iosApp中提供 SQLDelight 驱动的 actual 实现。 - Domain 层编排业务:编写 UseCase,只依赖 Repository 接口和 Kotlin 协程。
- UI 层消费状态:通过
viewModelScope收集 StateFlow,使用collectAsState()驱动 Compose 重组。 - 集成验收:编写跨平台单元测试(JVM + iOS 模拟器)验证数据流完整性。
1.7 验收标准
- 分层独立测试:Domain 层的 UseCase 不依赖任何 Android/iOS 框架,可在纯 JVM 环境运行。
- 状态一致性:同一个 Entity 在 Android 和 iOS 上修改后,两边数据最终一致(延迟不超过 2s)。
- 无循环依赖:Gradle 依赖图没有反向边,
gradle dependencies输出正常。 - 平台边界清晰:所有 platform-specific 代码集中在
actual模块,commonMain中无android或UIKit类型引用。 - 统一数据源写入唯一:通过代码审查确认没有绕过 Repository 直接写入数据库或文件。