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';
export default class EntryAbility extends UIAbility {
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) {
// 窗口可见
} else if (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 中,这里做一个可交互的模拟页面来理解流程。
interface LifecycleEvent {
name: string
time: string
detail: string
}
@Entry
@Component
struct UIAbilityDemoPage {
@State lifecycleLog: LifecycleEvent[] = []
@State currentPhase: string = 'onForeground'
@State launchMode: 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)
}
@Builder
PhaseBox(name: string, isActive: boolean) {
Text(name)
.fontSize(11)
.fontColor(isActive ? '#FFFFFF' : '#333333')
.padding(6)
.borderRadius(6)
.backgroundColor(isActive ? '#1a73e8' : '#E3F2FD')
}
private simulate(name: string, detail: string): void {
this.currentPhase = name
this.lifecycleLog.push({
name: name,
time: new Date().toLocaleTimeString(),
detail: detail
})
}
private getEventColor(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 展示
let newPage: string = want.parameters?.['page'] as string ?? ''
// 根据 newPage 跳转到对应页面
}
典型用法: 通知点击跳转——点击通知栏消息,通过 want.parameters 传目标页面,onNewWant 接收后跳转。
multiton——多实例
每次 startAbility 创建新实例,实例间完全独立。
{
"name": "NoteAbility",
"launchType": "multiton"
}
适用场景: 分屏操作、同时打开多个文档、多窗口并行——任务列表里显示多个任务。
specified——指定实例
开发者动态控制——通过 AbilityStage 的 onAcceptWant 返回 Key,匹配已有 Key 则复用,否则新建。
{
"name": "DocAbility",
"launchType": "specified"
}
// AbilityStage.ets
export default class MyAbilityStage extends AbilityStage {
onAcceptWant(want: Want): string {
// 返回 Key 决定复用还是新建
let docId: string = want.parameters?.['docId'] as string ?? ''
return `DocAbility_${docId}` // 同一 docId 复用实例
}
}
适用场景: 文档应用——重复打开同一文档复用实例(Key = docId),新建文档创建新实例。
启动模式选择指南
| 模式 | 实例数 | 任务列表 | 典型场景 |
|---|---|---|---|
| singleton | 1 | 1个任务 | 应用首页、设置、播放器 |
| multiton | N | N个任务 | 分屏、多文档、多窗口 |
| specified | 动态 | 动态 | 文档编辑、聊天窗口 |
决策树: 用户是否需要同时看到多个任务?不需要→singleton。需要多个但完全独立→multiton。需要多个但同Key复用→specified。
onNewWant 实战:通知跳转
最常见的 singleton + onNewWant 场景——点击通知跳转到指定页面。
// EntryAbility.ets
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
let targetPage: string = want.parameters?.['targetPage'] as string ?? ''
let targetId: string = want.parameters?.['targetId'] as string ?? ''
// 通过 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 |
更多推荐

所有评论(0)