分布式流转(Continuation)是 HarmonyOS 的杀手锏特性,它允许用户在一个设备上开始任务,然后在另一个设备上无缝继续。这不仅是跨端跳转,更是运行态栈(Runtime Stack)的迁移。
1. 分布式流转中的生命周期变化
流转过程涉及两个设备(源端和对端)的协同,生命周期并不是简单的“A 关 B 开”,而是 “数据同步 -> 异地重建 -> 状态确认” 。
源端(Source Device)
- onContinue(wantParam): 流转的发起阶段。系统回调此接口,询问是否允许流转。
- 保持 Foreground: 在对端成功启动并加载 UI 之前,源端不会进入后台或销毁。这是为了防止流转失败导致任务彻底丢失。
- 流转完成/销毁: 一旦对端确认成功接管,源端根据业务需求可以选择
terminateSelf(销毁)或者留在后台。
对端(Target Device)
- onCreate(want, launchParam): 冷启动。此时
launchParam.launchReason会被标记为CONTINUATION。 - onWindowStageCreate: 正常加载 UI。
- 数据恢复: 页面组件通过
aboutToAppear或onPageShow读取从源端传过来的序列化数据,恢复 UI 状态。
2. 状态如何序列化?
流转的本质是数据的跨端序列化。ArkTS 提供了 wantParam 作为数据的载体。
序列化规则:
- 基础类型:
string,number,boolean等可以直接放入wantParam.parameters。 - 复杂对象: 必须转换为 JSON 字符串 或 ArrayBuffer。
- UI 状态: 开发者需要手动保存。例如:
TextInput的光标位置、List的滚动偏移量、当前播放器的 Seek 时间点。
最佳实践:
不要试图通过流转传递“巨型”数据(如 100MB 的内存对象)。
- 原则: 传 ID 不传 实体。
- 机制: 源端将数据库 ID 传给对端,对端启动后利用分布式数据库(KV Store)或分布式文件系统同步拉取大数据量。
3. 流转失败如何回滚?
分布式环境复杂(Wi-Fi 断开、蓝牙干扰、对端内存不足),回滚机制(Rollback)是用户体验的最后一道防线。
失败检测机制
- 系统超时: 如果对端在规定时间内没有成功执行
loadContent,系统会通知源端流转失败。 - 逻辑拦截: 源端在
onContinue中可以返回REJECT(拒绝流转),例如当发现本地有未保存的敏感操作时。
如何处理回滚?
由于源端在流转期间一直处于 Foreground 或 后台活跃 状态,回滚其实是一个**“状态保持”**的过程:
- 用户感知: 源端界面弹窗提示“流转失败,请重试”。
- 资源恢复: 如果源端为了流转已经暂时禁用了某些传感器(如陀螺仪),需要在失败回调中重新激活。
- 数据一致性: 确保流转产生的临时标记位(如
isContinuing)被重置,防止应用逻辑陷入死循环。
4. 关键代码模式
在 UIAbility 中,流转的逻辑通常如下:
TypeScript
// 源端保存
onContinue(wantParam: {[key: string]: any}): AbilityConstant.OnContinueResult {
wantParam['progress'] = this.currentProgress; // 保存进度
return AbilityConstant.OnContinueResult.AGREE;
}
// 对端恢复
onCreate(want, launchParam) {
if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
this.restoredProgress = want.parameters['progress']; // 恢复进度
}
}
总结
| 特性 | 普通跳转 (startAbility) | 分布式流转 (Continuation) |
|---|---|---|
| 核心目的 | 切换功能模块 | 切换硬件设备 |
| 状态载体 | 基础 Want 参数 | 深度序列化 wantParam + 分布式数据 |
| 源端命运 | 通常进入 Background | 保持存活直至对端确认 |
| 失败后果 | 页面无法跳转 | 触发回滚,源端恢复交互 |
一句话建议: 把流转看作是一次“带行李的跨国旅行”。行李(数据)要打包得精简,护照(wantParam)要对齐,如果签证(连接)失败,赶紧回自己家(回滚)坐好。