HarmonyOS 6.0 UIAbility生命周期与多实例模式实战
UIAbility生命周期与多实例模式实战
页面生命周期(aboutToAppear/aboutToDisappear)只是冰山一角。UIAbility 才是应用级生命周期的核心——onCreate 初始化全局资源、onForeground 恢复传感器、onBackground 释放 GPS、onDestroy 关闭数据库。三种启动模式(singleton/multiton/specified)决定了实例复用还是新建。这篇把 UIAbility 的完整生命周期和启动模式讲清楚。
UIAbility 生命周期概览
UIAbility 的完整生命周期:onCreate → onWindowStageCreate → onForeground ↔ onBackground → onWindowStageDestroy → onDestroy
import{UIAbility,AbilityConstant,Want}from'@kit.AbilityKit';import{window}from'@kit.ArkUI';import{hilog}from'@kit.PerformanceAnalysisKit';exportdefaultclassEntryAbilityextendsUIAbility{onCreate(want:Want,launchParam:AbilityConstant.LaunchParam):void{hilog.info(0x0000,'EntryAbility','onCreate');}onWindowStageCreate(windowStage:window.WindowStage):void{hilog.info(0x0000,'EntryAbility','onWindowStageCreate');windowStage.loadContent('pages/Index');}onForeground():void{hilog.info(0x0000,'EntryAbility','onForeground');}onBackground():void{hilog.info(0x0000,'EntryAbility','onBackground');}onDestroy():void{hilog.info(0x0000,'EntryAbility','onDestroy');}}关键区别:组件生命周期是 UI 级别的,UIAbility 生命周期是应用级别的。onCreate 在进程冷启动时只执行一次,onForeground/onBackground 每次前后台切换都会触发。
各回调的最佳实践
onCreate——全局初始化
onCreate 在 UIAbility 实例创建时触发,只执行一次。适合做全局非 UI 资源初始化。
onCreate(want:Want,launchParam:AbilityConstant.LaunchParam):void{// 初始化数据库连接// 初始化网络库配置// 初始化日志/埋点系统// 读取持久化配置}禁忌:不要在 onCreate 里做 UI 操作(窗口还没创建),不要做耗时操作(会阻塞启动)。
onWindowStageCreate——加载页面
这是 UI 构建的起点,必须调用 windowStage.loadContent 加载主页面。
onWindowStageCreate(windowStage:window.WindowStage):void{// 订阅窗口事件windowStage.on('windowStageEvent',(data:window.WindowStageEventType)=>{if(data===window.WindowStageEventType.SHOWN){// 窗口可见}elseif(data===window.WindowStageEventType.HIDDEN){// 窗口隐藏}});// 加载主页面windowStage.loadContent('pages/Index');}onForeground/onBackground——资源管理
前后台切换时管理资源:前台申请、后台释放。
onForeground():void{// 恢复定位// 恢复传感器监听// 恢复动画// 重新申请 onBackground 释放的资源}onBackground():void{// 停止定位(省电)// 暂停动画// 释放摄像头/GPS// 保存临时数据// 注意:必须在 5 秒内完成}注意:onBackground 必须在 5 秒内完成,否则系统会杀进程。耗时保存操作应异步处理。
onDestroy——清理资源
UIAbility 销毁时触发。注意:用户按返回键不会触发 onDestroy,只有系统回收或杀进程才触发。
onDestroy():void{// 关闭数据库连接// 取消网络请求// 注销事件监听// 保存关键数据}模拟 UIAbility 生命周期 Demo
实际 UIAbility 回调在 EntryAbility.ets 中,这里做一个可交互的模拟页面来理解流程。
interfaceLifecycleEvent{name:stringtime:stringdetail:string}@Entry@Componentstruct UIAbilityDemoPage{@StatelifecycleLog:LifecycleEvent[]=[]@StatecurrentPhase:string='onForeground'@StatelaunchMode:string='singleton'build(){Column({space:16}){Text('UIAbility 生命周期模拟').fontSize(22).fontWeight(FontWeight.Bold).width('100%')Row({space:8}){this.PhaseBox('onCreate',this.currentPhase==='onCreate')Text('→').fontSize(16).fontColor('#999999')this.PhaseBox('onWindowStage\nCreate',this.currentPhase==='onWindowStageCreate')Text('→').fontSize(16).fontColor('#999999')this.PhaseBox('onForeground',this.currentPhase==='onForeground')}.width('100%').justifyContent(FlexAlign.Center)Row({space:8}){this.PhaseBox('onBackground',this.currentPhase==='onBackground')Text('↔').fontSize(16).fontColor('#999999')this.PhaseBox('onForeground',this.currentPhase==='onForeground')}.width('100%').justifyContent(FlexAlign.Center)Row({space:8}){this.PhaseBox('onDestroy',this.currentPhase==='onDestroy')this.PhaseBox('onNewWant',this.currentPhase==='onNewWant')}.width('100%').justifyContent(FlexAlign.Center)Row({space:8}){Button('冷启动').onClick(()=>this.simulate('onCreate','初始化全局资源'))Button('到前台').onClick(()=>this.simulate('onForeground','恢复定位/传感器'))Button('到后台').onClick(()=>this.simulate('onBackground','释放GPS/摄像头'))Button('onNewWant').onClick(()=>this.simulate('onNewWant','接收新参数'))Button('销毁').onClick(()=>this.simulate('onDestroy','关闭数据库'))}ForEach(this.lifecycleLog.slice().reverse(),(event:LifecycleEvent)=>{Row({space:8}){Text(event.time).fontSize(11).fontColor('#999999').width(60)Text(event.name).fontSize(13).fontWeight(FontWeight.Medium).fontColor(this.getEventColor(event.name)).width(100)Text(event.detail).fontSize(12).fontColor('#666666').layoutWeight(1)}.width('100%').padding(4)},(event:LifecycleEvent,index:number)=>`${index}`)}.width('100%').padding(20)}@BuilderPhaseBox(name:string,isActive:boolean){Text(name).fontSize(11).fontColor(isActive?'#FFFFFF':'#333333').padding(6).borderRadius(6).backgroundColor(isActive?'#1a73e8':'#E3F2FD')}privatesimulate(name:string,detail:string):void{this.currentPhase=namethis.lifecycleLog.push({name:name,time:newDate().toLocaleTimeString(),detail:detail})}privategetEventColor(name:string):string{if(name==='onCreate')return'#1565C0'if(name==='onForeground')return'#E65100'if(name==='onBackground')return'#C62828'if(name==='onNewWant')return'#6A1B9A'return'#333333'}}三种启动模式
singleton——单实例(默认)
全局唯一实例。再次 startAbility 不会走 onCreate,而是走 onNewWant。
// module.json5 { "name": "EntryAbility", "launchType": "singleton" }适用场景:应用首页、设置页、播放器页——任务列表里只显示一个任务。
// 再次启动已有 singleton 实例时触发onNewWant(want:Want,launchParam:AbilityConstant.LaunchParam):void{// 从 want.parameters 获取新参数// 更新 UI 展示letnewPage:string=want.parameters?.['page']asstring??''// 根据 newPage 跳转到对应页面}典型用法:通知点击跳转——点击通知栏消息,通过 want.parameters 传目标页面,onNewWant 接收后跳转。
multiton——多实例
每次 startAbility 创建新实例,实例间完全独立。
{ "name": "NoteAbility", "launchType": "multiton" }适用场景:分屏操作、同时打开多个文档、多窗口并行——任务列表里显示多个任务。
specified——指定实例
开发者动态控制——通过 AbilityStage 的 onAcceptWant 返回 Key,匹配已有 Key 则复用,否则新建。
{ "name": "DocAbility", "launchType": "specified" }// AbilityStage.etsexportdefaultclassMyAbilityStageextendsAbilityStage{onAcceptWant(want:Want):string{// 返回 Key 决定复用还是新建letdocId:string=want.parameters?.['docId']asstring??''return`DocAbility_${docId}`// 同一 docId 复用实例}}适用场景:文档应用——重复打开同一文档复用实例(Key = docId),新建文档创建新实例。
启动模式选择指南
| 模式 | 实例数 | 任务列表 | 典型场景 |
|---|---|---|---|
| singleton | 1 | 1个任务 | 应用首页、设置、播放器 |
| multiton | N | N个任务 | 分屏、多文档、多窗口 |
| specified | 动态 | 动态 | 文档编辑、聊天窗口 |
决策树:用户是否需要同时看到多个任务?不需要→singleton。需要多个但完全独立→multiton。需要多个但同Key复用→specified。
onNewWant 实战:通知跳转
最常见的 singleton + onNewWant 场景——点击通知跳转到指定页面。
// EntryAbility.etsonNewWant(want:Want,launchParam:AbilityConstant.LaunchParam):void{lettargetPage:string=want.parameters?.['targetPage']asstring??''lettargetId:string=want.parameters?.['targetId']asstring??''// 通过 EventHub 或 AppStorage 通知页面跳转AppStorage.setOrCreate('targetPage',targetPage)AppStorage.setOrCreate('targetId',targetId)}// Index.ets 中监听@State@Watch('onTargetPageChange')targetPage:string=AppStorage.get('targetPage')??''onTargetPageChange():void{if(this.targetPage){// 跳转到目标页面router.pushUrl({url:this.targetPage})AppStorage.setOrCreate('targetPage','')}}要点:singleton 模式下通知点击不会走 onCreate,所以必须在 onNewWant 里接收参数。通过 AppStorage 或 EventHub 把参数传给页面层。
踩坑清单
| 问题 | 原因 | 解决 |
|---|---|---|
| onNewWant 不触发 | launchType 不是 singleton | singleton 模式才有 onNewWant |
| onCreate 里操作 UI | 窗口还没创建 | UI 操作放 onWindowStageCreate |
| onBackground 超时被杀 | 5秒限制 | 耗时操作异步处理 |
| specified 模式不生效 | 没实现 AbilityStage | 需实现 onAcceptWant 返回 Key |
| 通知点击无反应 | 未处理 onNewWant | singleton 模式下处理 onNewWant |
| 返回键退出后数据丢失 | onDestroy 不一定触发 | onBackground 里就保存关键数据 |
| multiton 内存泄漏 | 多实例未释放 | 每个实例 onDestroy 清理资源 |
| onWindowStageEvent 不触发 | 未订阅 | 在 onWindowStageCreate 里订阅 |
| want.parameters 取值为空 | 参数未传或 key 错误 | 检查发送方和接收方的 key 一致性 |
| 冷启动白屏 | loadContent 延迟 | onWindowStageCreate 尽早 loadContent |
