发布时间:2026/8/12 16:25:27
HarmonyOS 6.0 应用接续onContinue——手机编辑到一半,平板接着搞 写笔记写到一半要出门手机一划就转到平板继续——不是云同步那种保存-重新打开而是真正的无缝接续页面栈、滚动位置、输入内容全部原样恢复。HarmonyOS NEXT 的应用接续Continuation就是干这个的。这篇把 onContinue 保存、onCreate 恢复、continuable 配置的完整链路讲清楚。应用接续概览核心概念onContinue——源端手机保存迁移数据写入 wantParamonCreate/onNewWant——对端平板接收迁移数据恢复 UIcontinuable——module.json5 中声明 Ability 支持接续LaunchReason.CONTINUATION——对端通过启动原因判断是接续还是正常启动import{UIAbility,AbilityConstant,Want}fromkit.AbilityKit配置 continuablemodule.json5{ module: { name: entry, type: entry }, abilities: [ { name: EntryAbility, continuable: true, launchType: singleton } ] }要点continuable: true 是必须配置的否则系统不会触发接续流程。launchType 建议用 singleton避免对端出现多实例。源端onContinue 保存数据用户发起迁移时源端 UIAbility 的 onContinue 被触发exportdefaultclassEntryAbilityextendsUIAbility{privatecontent:stringprivatescrollY:number0privateeditMode:stringonContinue(wantParam:Recordstring,Object):AbilityConstant.OnContinueResult{// 保存业务数据到 wantParamwantParam[content]this.content wantParam[scrollY]this.scrollY.toString()wantParam[editMode]this.editMode wantParam[lastEditTime]newDate().toLocaleString()console.info(onContinue: 数据已保存)// 返回 AGREE 表示同意迁移returnAbilityConstant.OnContinueResult.AGREE// 返回 REJECT 表示拒绝迁移如数据未保存// return AbilityConstant.OnContinueResult.REJECT// 返回 MISMATCH 表示版本不匹配// return AbilityConstant.OnContinueResult.MISMATCH}}要点wantParam 的 value 必须是 Object 类型string、number 等复杂对象需要 JSON.stringify 序列化。返回 AGREE 才会继续迁移流程。对端onCreate 恢复数据对端设备的 UIAbility 被启动launchReason 为 CONTINUATIONexportdefaultclassEntryAbilityextendsUIAbility{privatecontent:stringprivatescrollY:number0onCreate(want:Want,launchParam:AbilityConstant.LaunchParam):void{// 判断是否为接续启动if(launchParam.launchReasonAbilityConstant.LaunchReason.CONTINUATION){// 从 want.parameters 恢复数据if(want.parameters!undefined){letparams:Recordstring,Objectwant.parametersthis.contentparams[content]asstringletscrollYStr:stringparams[scrollY]asstringthis.scrollYparseInt(scrollYStr,10)}console.info(onCreate: 接续数据已恢复)}else{// 正常启动console.info(onCreate: 正常启动)}}}要点必须通过 launchReason 判断是否为接续启动否则正常启动也会走恢复逻辑。want.parameters 和源端 onContinue 的 wantParam 是同一份数据。对端onRestoreData 恢复 UI可选如果需要在恢复后做 UI 特定操作onRestoreData(wantParam:Recordstring,Object):void{// 已废弃建议在 onCreate 中处理// 此回调仅作兼容保留}要点新版本推荐在 onCreate 中直接恢复onRestoreData 已废弃。完整迁移流程源端(手机) 对端(平板) │ │ │ 用户点击迁移按钮 │ │ │ │ onContinue() │ │ ├─ 保存数据到wantParam │ │ └─ return AGREE │ │ │ │ ───── 系统传输数据 ──────→ │ │ │ │ onCreate(want, launchParam) │ ├─ launchReason CONTINUATION │ ├─ 从want.parameters恢复数据 │ └─ 重建UI │ │ │ 源端onStoreData() │ │ └─ 可选保存源端状态 │ │ │ │ onWindowStageRestore() │ └─ 恢复窗口内容页面级数据恢复Ability 层恢复数据后需要传递给页面// EntryAbility.etsonCreate(want:Want,launchParam:AbilityConstant.LaunchParam):void{if(launchParam.launchReasonAbilityConstant.LaunchReason.CONTINUATION){letparams:Recordstring,Objectwant.parametersasRecordstring,Object// 通过 AppStorage 传递给页面AppStorage.setOrCreate(continuation_content,params[content]asstring)AppStorage.setOrCreate(continuation_scrollY,params[scrollY]asstring)}}// 页面中接收StorageLink(continuation_content)content:stringStorageLink(continuation_scrollY)scrollYStr:string0要点Ability 和 Page 是两个不同的上下文通过 AppStorage 或 LocalStorage 桥接数据。大数据迁移策略wantParam 有大小限制约 100KB大数据需要用文件或数据库中转onContinue(wantParam:Recordstring,Object):AbilityConstant.OnContinueResult{// 小数据直接放 wantParamwantParam[title]this.title wantParam[cursorPos]this.cursorPos.toString()// 大数据写入临时文件wantParam 只传文件路径if(this.largeData.length50000){letfilePath:stringthis.getContext().tempDir/continuation_data.jsonfs.writeTextSync(filePath,JSON.stringify(this.largeData))wantParam[dataFilePath]filePath wantParam[hasLargeData]true}else{wantParam[content]this.largeData wantParam[hasLargeData]false}returnAbilityConstant.OnContinueResult.AGREE}要点系统会自动传输源端的文件目录files/temp/cache到对端所以文件路径中转是可行的。迁移失败处理onContinue(wantParam:Recordstring,Object):AbilityConstant.OnContinueResult{// 有未保存的草稿if(this.hasUnsavedChanges){// 弹窗提示用户returnAbilityConstant.OnContinueResult.REJECT}// 版本不兼容if(this.localVersionthis.targetVersion){returnAbilityConstant.OnContinueResult.MISMATCH}returnAbilityConstant.OnContinueResult.AGREE}要点REJECT 拒绝迁移用户可感知MISMATCH 版本不匹配系统处理AGREE 同意迁移。不要无条件返回 AGREE未保存的数据可能丢失。完整 Demo 代码Demo 模拟了笔记编辑→选择目标设备→迁移流程动画的全过程。interfaceMigrationStep{name:string;status:string;detail:string;}EntryComponentstruct ContinuationDemo{StatemigrationSteps:MigrationStep[][];StatecurrentPage:string笔记内容编辑中...;StatetargetDevice:string;StateisMigrating:booleanfalse;StatemigrateResult:string;StateeditContent:string这是跨设备接续的笔记内容;StatescrollPosition:number0;StateavailableDevices:string[][华为MatePad Pro,华为智慧屏,华为MateBook];build(){Column({space:0}){Row(){Button( 返回).fontSize(14).backgroundColor(Color.Transparent).fontColor(#1a73e8).onClick((){router.back();})Text(应用接续迁移).fontSize(18).fontWeight(FontWeight.Bold).layoutWeight(1).textAlign(TextAlign.Center)Text(this.isMigrating?迁移中:就绪).fontSize(12).fontColor(this.isMigrating?#F44336:#4CAF50)}.width(100%).height(56).padding({left:12,right:12}).alignItems(VerticalAlign.Center).backgroundColor(#FFFFFF)Scroll(){Column({space:16}){Column({space:12}){Text(模拟编辑场景).fontSize(16).fontWeight(FontWeight.Bold).width(100%)Text(手机编辑笔记 → 一键迁移到平板继续).fontSize(13).fontColor(#999999).width(100%)TextArea({text:this.editContent,placeholder:编辑笔记内容...}).width(100%).height(120).onChange((value:string){this.editContentvalue;})Row(){Text(滚动位置: this.scrollPositionpx).fontSize(12).fontColor(#999999).layoutWeight(1)Button(模拟滚动).onClick((){this.scrollPosition256;})}}.width(100%).padding(16).borderRadius(12).backgroundColor(#FFFFFF)Column({space:12}){Text(目标设备).fontSize(16).fontWeight(FontWeight.Bold).width(100%)ForEach(this.availableDevices,(device:string){Row({space:8}){Radio({value:device,group:devices}).onChange((isChecked:boolean){if(isChecked){this.targetDevicedevice;}})Text(device).fontSize(14).layoutWeight(1)}.width(100%).padding(8)},(device:string)device)Button(发起迁移).width(100%).enabled(this.targetDevice.length0!this.isMigrating).onClick((){this.startMigration();})}.width(100%).padding(16).borderRadius(12).backgroundColor(#FFFFFF)if(this.migrationSteps.length0){Column({space:8}){Text(迁移流程).fontSize(16).fontWeight(FontWeight.Bold).width(100%)ForEach(this.migrationSteps,(step:MigrationStep,index:number){Row({space:8}){Text((index1).toString().).fontSize(13).fontWeight(FontWeight.Bold).fontColor(this.getStepColor(step.status)).width(24)Column({space:2}){Text(step.name).fontSize(14).fontWeight(FontWeight.Medium)Text(step.detail).fontSize(12).fontColor(#999999)}.layoutWeight(1).alignItems(HorizontalAlign.Start)Text(step.status).fontSize(11).fontColor(#FFFFFF).backgroundColor(this.getStepColor(step.status)).borderRadius(4).padding({left:6,right:6,top:2,bottom:2})}.width(100%).padding(8).borderRadius(6).backgroundColor(#FAFAFA)},(step:MigrationStep,index:number)${index})}.width(100%).padding(16).borderRadius(12).backgroundColor(#FFFFFF)}if(this.migrateResult){Text(this.migrateResult).fontSize(14).fontColor(#4CAF50).padding(12).borderRadius(8).backgroundColor(#E8F5E9).width(100%)}}.padding(16)}.layoutWeight(1).width(100%)}.width(100%).height(100%).backgroundColor(#F5F5F5)}privategetStepColor(status:string):string{if(status完成)return#4CAF50if(status进行中)return#FF9800return#9E9E9E}privatestartMigration():void{this.isMigratingtruethis.migrationSteps[]this.migrateResultletsteps:MigrationStep[][{name:源端 onContinue,status:等待,detail:保存当前页面状态到wantParam},{name:系统传输数据,status:等待,detail:跨设备传输wantParam和页面栈},{name:对端 onCreate,status:等待,detail:LaunchReason.CONTINUATION触发恢复},{name:对端恢复UI,status:等待,detail:恢复内容和滚动位置}]this.migrationStepsstepsletstepIndex:number0letintervalId:numbersetInterval((){if(stepIndexthis.migrationSteps.length){this.migrationSteps[stepIndex].status进行中setTimeout((){this.migrationSteps[stepIndex].status完成stepIndexif(stepIndexthis.migrationSteps.length){clearInterval(intervalId)this.isMigratingfalsethis.migrateResult迁移完成笔记内容已同步到this.targetDevice}},800)}},1000)this.migrationSteps[0].status进行中setTimeout((){this.migrationSteps[0].status完成this.migrationSteps[0].detail已保存: contentthis.editContent, scrollYthis.scrollPosition stepIndex1},800)}}应用接续 vs 分布式数据对象对比应用接续分布式数据对象触发方式用户主动迁移修改属性自动同步数据流向单向源→对端双向实时同步恢复内容页面栈数据仅数据使用场景换设备继续用多设备实时协同用户体验明确的迁移动画无感知自动同步要点接续是搬家——把整个应用状态搬过去分布式对象是同步——数据实时保持一致。两者可以配合使用。踩坑清单问题原因解决onContinue 不触发continuable 未配置module.json5 设 continuable: true对端 onCreate launchReason 不对对端不是接续启动检查 launchReason 是否为 CONTINUATION恢复数据为空wantParam value 类型不对value 必须是 Object复杂对象 JSON.stringify迁移大图失败wantParam 超过大小限制大数据用文件中转传文件路径对端页面空白数据未传递到 Page通过 AppStorage/LocalStorage 桥接迁移后源端卡住未正确返回 AGREEonContinue 必须返回 OnContinueResult两端版本不同崩溃数据结构不兼容检查版本号返回 MISMATCHsingleton 模式冲突对端已有实例运行singleton 会复用实例onNewWant 接收数据滚动位置恢复不准onWindowStageRestore 时机windowStage 加载完成后再设置滚动网络断开迁移失败蓝牙/WiFi 不稳定迁移前检查网络失败后重试

相关新闻

2026/8/12 16:25:27

Typora字体自定义全攻略:提升写作效率与视觉舒适度

1. 项目概述:为什么我们要折腾Typora的字体? 作为一名长期与文字打交道的创作者,我几乎每天都要在Typora里泡上好几个小时。它简洁的界面和流畅的Markdown体验,让它成为了我记录笔记、撰写草稿甚至完成正式文档的主力工具。但用久…

2026/8/12 16:25:27

华硕笔记本风扇静音终极指南:用G-Helper实现完美平衡

华硕笔记本风扇静音终极指南:用G-Helper实现完美平衡 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook, Exp…

2026/8/12 16:25:27

终极AO3镜像站解决方案:3分钟解锁全球同人创作宝库

终极AO3镜像站解决方案:3分钟解锁全球同人创作宝库 【免费下载链接】AO3-Mirror-Site 项目地址: https://gitcode.com/gh_mirrors/ao/AO3-Mirror-Site Archive of Our Own(AO3)作为全球最大的非营利性同人创作平台,汇聚了…

2026/8/12 17:35:34

人生代码|第3关:引入好工具—— 重造轮子,努力白干

本篇属于第一篇输入篇|核心命题:筛选入参第2关我们学会了一件事:拒绝有毒参数。把坏的挡在门外,你的系统干净了,安全了,不再被消耗了。但然后呢?干净 ≠ 强大。一个只做“拒绝”的系统&#xff…

2026/8/12 17:35:34

IAR EWARM调试环境深度配置:从基础到高级实战指南

在实际嵌入式开发项目中,调试器(Debugger)和集成开发环境(IDE)的选择与配置,往往直接决定了开发效率和问题排查的深度。一个功能强大、配置得当的调试环境,就如同拥有“炮多弹多”的火力优势&am…

2026/8/12 17:35:34

库存周转率怎么算?用这个指标一眼看穿库存是积压还是缺货

【摘要】库存周转率是库存管理的核心指标之一,它告诉你库存"转"得有多快——是积压了还是缺货了。本文详解库存周转率的计算方法和实际应用。1 什么是库存周转率库存周转率:一定周期内(通常是一个月或一年)&#xff0c…

2026/8/12 17:35:34

彻底解决Python UnicodeEncodeError:从gbk编码错误到UTF-8最佳实践

1. 问题缘起:一个看似简单却无处不在的编码“幽灵” “UnicodeEncodeError: ‘gbk‘ codec can‘t encode character ‘\xe5‘ in position 13”,这个错误信息对于任何使用Python处理过中文文本的开发者来说,都绝不陌生。它就像一个幽灵&…

2026/8/12 17:35:34

RTT-串口与485总线

1. UART 是什么?UART(通用异步收发器)是最常用的串行通信接口,通过两根线完成全双工通信:TX:发送线。RX:接收线。UART 不需要时钟线,通信双方通过约定相同的波特率、数据位、停止位和…

2026/8/12 17:30:33

大厂的 GPU 为什么比你利用率高一倍?动态调度底层原理

GPU 动态调度全解:为啥你显卡常年 30% 利用率,大厂轻松干到 70% 一、整体简介绝大多数个人、小团队部署模型都是静态绑卡调度,任务启动直接独占整张 GPU,哪怕只占用三四成算力,剩余资源完全闲置,日常 GPU 利用率常年卡在 30%~40%。 而字节、月之暗面、阿里这类大厂依靠分…

2026/8/12 10:37:12

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/12 5:35:25

当 LLM 遇见大文档:主流开源项目如何处理上下文超限

从 Agentic Loop 到 Repo Map,七种策略与六类陷阱引言:128K vs 10MB 的硬冲突 2026 年的 LLM 上下文窗口已达到 128K ~ 1M token(≈ 0.5MB ~ 4MB 文本),但 LLM 想要处理的真实数据规模远远超过这个量级:真实…

2026/8/12 9:34:08

Ubuntu 23.10中双击运行.sh文件的完整指南:从权限原理到桌面配置

1. 项目概述:从一次“双击”引发的权限探索在Ubuntu桌面环境下,我们习惯了双击运行那些带有.exe后缀的Windows程序安装包,但当你拿到一个以.sh结尾的Shell脚本文件时,满怀期待地双击它,却很可能只看到一个文本编辑器窗…

2026/8/12 9:34:08

NumPy条件索引实战:np.where与np.argwhere高效数据筛选指南

1. 从一次数据筛选的“笨办法”说起 前几天,我帮一个刚入行的数据分析师同事看代码,他正在处理一批传感器数据,需要找出所有温度超过阈值的数据点,然后进行后续分析。我一看他的实现,好家伙,一个 for 循环…

2026/8/12 9:34:08

基于Docker与Selenium Grid构建高可用浏览器自动化测试环境

1. 项目概述:为什么需要容器化的浏览器自动化?在软件开发和测试领域,浏览器自动化早已不是新鲜事。无论是日常的UI回归测试、数据抓取,还是复杂的业务流程模拟,Selenium都是我们绕不开的利器。然而,但凡在团…

2026/8/10 11:20:30

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/11 17:06:59

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/11 3:05:11

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…