1. Compose埋点架构全景:状态层、事件层、上报层
在 Jetpack Compose 的声明式 UI 体系下,埋点数据不再由用户点击事件被动触发,而是由状态驱动自动流转。传统的 Activity/Fragment 埋点方案在 Compose 中面临 状态感知缺失、组合生命周期不可控、上报时机混乱 三大核心问题。本章从架构全景出发,定义 状态层 → 事件层 → 上报层 的三层边界,给出每一层的组件职责与数据流契约。
1.1 三层架构总览
整个埋点流转体系划分为三个彼此独立、通过接口通信的层级。状态层感知 Compose 状态变化并生成原始事件;事件层对原始事件进行校验、增强、缓冲和策略过滤;上报层负责将合规事件序列化、批量压缩并发送到远端服务。三层之间不允许跨层调用,也不允许反向依赖。
| 层级 | 边界 | 核心职责 | 对外依赖 |
|---|---|---|---|
| 状态层 | Compose 运行时 + ViewModel | 监听 Snapshot 快照变化,采集状态快照并包装为原始事件 | Compose State / SnapshotFlow |
| 事件层 | ViewModel / UseCase / Repository | 事件去重、合并、采样、增强业务上下文 | Coroutine Flow / Channel |
| 上报层 | 网络模块 / 本地持久化 | 批量打包、重试、配额控制、远端写⼊ | OkHttp / Retrofit / Room |
设计原则: 每一层的修改不应影响其他层的逻辑。状态层只关心“发生了什么状态变化”,事件层只关心“如何加工事件”,上报层只关心“如何可靠送达”。
1.2 边界与组件职责
三层之间的边界由 不可变事件契约 定义。状态层输出的 RawEvent 只包含状态快照和版本戳;事件层输出的 TrackEvent 携带业务维度、采样标记和路由标签;上报层最终消费 ReportPacket 进行序列化与传输。
- 状态层 — 唯一允许直接依赖
Compose State/SnapshotFlow的层级。负责将mutableStateOf的变化映射为事件流,不对事件做任何业务判断。 - 事件层 — 纯 Kotlin 协程模块,不依赖任何 Android 或 Compose 运行时。负责事件的 去重(Dedup)、采样(Sampling)、上下文增强(Enrich) 和 缓冲(Buffer)。
- 上报层 — 依赖网络框架和本地数据库。负责将事件打包为 JSON/Protobuf,通过 批量合并 降低请求次数,并通过 指数退避重试 保证最终可达。
边界检查清单: 状态层代码中禁止出现“上报”或“网络”字样;事件层代码中禁止出现
Compose 或 View 导入;上报层代码中禁止出现 mutableStateOf 或 snapshotFlow 调用。
1.3 数据流与控制流
数据流是单向的:状态 → 事件 → 上报。控制流则通过 策略注入 反向作用于事件层和上报层,例如采样率更新、上报频率调节、事件黑名单等。
// 状态层:通过 SnapshotFlow 感知 Compose 状态变化
@Composable
fun TrackableScreen(viewModel: TrackableViewModel) {
val uiState by viewModel.uiState.collectAsState()
// 状态层自动采集
LaunchedEffect(uiState) {
viewModel.stateLayer.emitRawEvent(
RawEvent(
snapshot = uiState.toSnapshot(),
version = snapshotFlow { uiState }.first()
)
)
}
}
// 事件层:处理并转发
fun EventProcessor.process(raw: RawEvent): TrackEvent? {
return when {
raw.isDuplicate() -> null // 去重
!sampler.shouldSample(raw) -> null // 采样
else -> raw.enrich(metadataProvider()) // 增强
}
}
// 上报层:批量调度
suspend fun ReportDispatcher.dispatch(event: TrackEvent) {
buffer.put(event)
if (buffer.size >= batchSize) {
uploader.upload(buffer.flush())
}
}
1.4 信任链路与版本追踪
数据在层间流转时,必须携带 不可篡改的签名链。每一层在收到前层数据后,会追加自己的校验值再传递给下一层。状态层为每个 RawEvent 生成 snapshotVersion;事件层附加 eventSignature(业务 ID + 时间戳 HMAC);上报层写入 reportChecksum 后持久化。
风险点: 如果状态层在 Composable 重组期间多次发射相同快照,事件层必须实现幂等去重,否则会导致同一状态被上报多次。推荐在 EventProcessor 中维护一个 LRU 缓存,以
snapshotVersion 为键做去重。
1.5 选型权衡
| 决策点 | 方案 A | 方案 B | 推荐场景 |
|---|---|---|---|
| 状态采集方式 | SnapshotFlow + State | Compose 效应 + 手动发射 | 统一用 SnapshotFlow,避免效应泄漏 |
| 事件缓冲位置 | 内存 Channel (Buffer) | Room 持久化缓冲 | 低频事件用内存,高频/重要事件用 Room |
| 上报触发策略 | 定时批量 (10s 窗口) | 阈值触发 (满 N 条立即上报) | 对实时性要求不高时用定时批量,降低请求量 |
| 重试机制 | 指数退避 + 最大 3 次 | 线性重试 + 持久化队列 | 网络不稳定场景用指数退避;离线场景用持久化队列 |
1.6 落地步骤与验收标准
将三层架构落地到现有 Compose 项目中,建议按以下顺序推进:
- 裁剪状态层 — 在目标 Composable 中注入
StateLayer,定义要追踪的 State 变量列表,验证每次状态变化都能产出 RawEvent。 - 搭建事件层流水线 — 实现 EventCollector + EventProcessor + EventBuffer,用单元测试验证去重和采样逻辑。
- 对接上报层 — 接入网络 SDK,配置批量上传参数和重试策略,编写集成测试验证端到端上报。
- 注入控制流 — 通过 ViewModel 或配置中心下发采样率、黑名单等策略,观察事件层是否按预期过滤。
- 全链路压测 — 在 200+ 状态变化/秒的极限场景下,验证事件层不 OOM、上报层不丢数据。
验收标准(每个标准必须可量化测试):
✅ 状态层每秒 500 次快照发射时,事件层丢事件率 < 0.01%。
✅ 上报层在弱网环境(丢包率 30%)下,24 小时内事件最终送达率 > 99.9%。
✅ 三层代码之间无循环依赖,编译期可通过
✅ 单次链路延迟(状态变化 → 上报写入)不超过 500ms(Wi-Fi 环境)。
✅ 状态层每秒 500 次快照发射时,事件层丢事件率 < 0.01%。
✅ 上报层在弱网环境(丢包率 30%)下,24 小时内事件最终送达率 > 99.9%。
✅ 三层代码之间无循环依赖,编译期可通过
module-info 或 gradle 依赖检查验证。✅ 单次链路延迟(状态变化 → 上报写入)不超过 500ms(Wi-Fi 环境)。