3. Wear OS应用架构与生命周期
Wear OS 上的健康应用很少只由一个界面构成。用户抬手看表时可能只看到表盘上的一个心率数字,点进去才进入完整测量界面;后台又要持续采集传感器数据,并在异常时发出提醒。这些体验分别由不同组件承担:Activity 负责前台交互,Service(尤其是前台服务)负责持续采集,Complication 把关键指标嵌入表盘,Tile 提供一瞥即得的快捷入口。理解它们的职责边界与交互方式,是设计健康应用架构的第一步。
四类组件的职责定位
Activity 是用户可见、可交互的界面载体。在健康场景中,它通常承载“测量心率”“查看今日步数曲线”“开始一次跑步记录”这类需要用户专注操作的任务。Activity 的生命周期受用户和系统共同支配:进入前台时 onResume,被表盘遮挡或息屏时 onPause,系统内存紧张时可能被销毁。因此 Activity 不适合承担长时间采集,一旦用户离开界面,采集逻辑就可能被中断。
Service 用于在后台执行不依赖界面的工作。健康应用中最常用的是前台服务(Foreground Service),它必须显示一条常驻通知,系统才允许其长期运行。持续心率监测、运动轨迹记录、睡眠阶段推断都适合放在前台服务中。它不随 Activity 销毁而停止,从而保证数据连续性。
Complication 是表盘上的数据插槽。它本身不绘制复杂界面,而是向表盘提供一小块数据或短文本,例如当前心率、今日步数、血氧值。表盘按自己的样式渲染,应用只负责按系统请求更新数据。它的价值在于“零点击可见”。
Tile 是用户从表盘滑动进入的快捷面板,用少量控件展示信息并提供一两个操作入口,例如“开始测量”“查看最近一次心率”。它比 Activity 轻,比 Complication 承载的信息更多,适合作为高频操作的跳板。
组件之间的交互关系
这四类组件并非孤立,而是围绕同一份健康数据协同工作。典型链路是:前台服务持续采集并写入本地数据层(如 Room 数据库或 Data Layer);Complication 定期从数据层读取最新值推送给表盘;Tile 读取同一数据层展示摘要,并在用户点击时通过 Intent 或 RemoteActivityHelper 拉起 Activity;Activity 则负责详细展示与用户主动发起的测量。
图中可以看到,前台服务是数据的主要生产者,数据层是共享枢纽,Complication、Tile、Activity 都是数据的消费者或读写者。这种“单一数据源 + 多消费者”的结构,避免了各组件各自维护状态导致的数据不一致。
生命周期与数据一致性
健康数据对连续性敏感,因此要特别关注各组件的生命周期差异。Activity 被销毁时,正在进行的测量若只写在 Activity 内就会丢失;正确做法是把采集逻辑放在前台服务,Activity 只订阅数据并展示。Complication 的更新由系统调度,不能假设它实时刷新,因此它读取的应是数据层中已落库的最新值,而不是临时内存变量。Tile 在用户滑入时创建、滑出后可能被销毁,所以它不应持有长连接,而应在每次进入时重新读取数据层。
一个常见的坑是:在 Activity 中直接启动一个普通后台 Service 做持续采集。Android 8.0 以后后台服务受限,应用退到后台后服务很快会被停止,导致心率曲线出现断点。正确选择是使用 startForegroundService() 并在 5 秒内调用 startForeground() 显示通知。下面是一个前台服务启动采集的骨架示例:
class HeartRateService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = buildNotification() // 常驻通知,含心率值
startForeground(NOTIF_ID, notification) // 必须在 5 秒内调用
startCollecting() // 启动传感器采集协程
return START_STICKY
}
private fun startCollecting() {
scope.launch {
sensorClient.heartRateFlow().collect { bpm ->
repository.insert(HeartRateRecord(bpm, System.currentTimeMillis()))
updateNotification(bpm) // 同步刷新通知
}
}
}
}
采集到的每条记录都写入 repository,Complication 和 Tile 后续从同一仓库读取,从而保证表盘、快捷面板和详情页看到的是同一份数据。
Complication 与 Tile 的更新时机
Complication 通过 ComplicationDataSourceService 响应表盘的更新请求。系统会在合适时机调用 onComplicationRequest,应用在其中返回当前值。健康场景中,心率这类高频变化的数据不宜每次变化都推送,否则耗电明显;更合理的策略是设定最小更新间隔,例如 60 秒,或在数值跨越阈值(如静息心率超过 100)时才主动请求刷新。
Tile 通过 TileService 的 onStartListening 与 onStopListening 管理生命周期。进入时读取数据层并构建布局,退出时释放监听。若 Tile 上放置“开始测量”按钮,点击后应通过 RemoteActivityHelper.startRemoteActivity() 拉起 Activity,而不是在 Tile 内直接执行长时间任务。
组件选择速查
| 需求 | 首选组件 | 原因 |
|---|---|---|
| 持续记录跑步心率 | 前台服务 | 不随界面销毁,可长期运行 |
| 表盘显示当前步数 | Complication | 零点击可见,由表盘渲染 |
| 快速开始一次测量 | Tile | 滑入即用,可拉起 Activity |
| 查看历史曲线与详情 | Activity | 需要完整交互界面 |
| 异常心率提醒 | 前台服务 + 通知 | 后台判断并主动触达用户 |
把这张表与前面的架构图对照,可以快速判断一个新功能应该落在哪个组件上。核心判断依据是:它是否需要用户持续注视(Activity)、是否需要脱离界面长期运行(前台服务)、是否只需一瞥可见(Complication)、是否是高频操作的快捷入口(Tile)。四者通过共享数据层协作,共同构成完整的健康应用体验。