Harmony os------UIAbility 组件生命周期|我按自己的理解梳了一遍
这一篇是我在看官方文档时,自己消化后重写的版本,主要讲: UIAbility 在什么时候活过来、什么时候进前台 / 后台、什么时候被销毁,以及每个生命周期回调适合放什么逻辑。
1. 先搞清楚:UIAbility 的"几种状态"
从用户的角度看,一个 UIAbility 大概会经历这几种状态:
- 被创建:第一次启动时
- 进入前台:界面可见、可交互
- 切到后台:界面不可见了
- 被销毁:整个能力不再使用
从开发者的角度,对应的核心生命周期回调就是:
onCreate()-- 实例第一次创建onWindowStageCreate()-- 窗口(WindowStage)准备好,装 UI 的时候onForeground()-- 进入前台(UI 即将可见 / 可交互)onBackground()-- 进入后台(UI 完全不可见)onWindowStageWillDestroy()-- 窗口将被销毁(还能操作 WindowStage)onWindowStageDestroy()-- 窗口已销毁(释放 UI 资源)onDestroy()-- Ability 实例整个要结束onNewWant()-- 已经存在的 UIAbility 再次被拉起时,用来"更新参数"的
一个很重要的点: 这些生命周期回调都是在"主线程"执行的,所以里面要尽量保持"轻量",耗时逻辑丢给子线程或异步。
2. 两种常见启动场景
官方文档里把 UIAbility 的生命周期拆成两个典型场景,我照着再说一遍:
2.1 场景一:正常启动到前台
这个是最常见的情况:用户点图标、点卡片、点通知,启动一个 UIAbility。
完整流程大概是:
-
首次启动时
onCreate()onWindowStageCreate()onForeground()
-
用户切到其他应用(当前 UIAbility 退到后台)
onBackground()
-
用户再切回来
onNewWant()(如果是再次通过 want 启动)onForeground()
小记:
onCreate()整个生命周期只跑 一次。- 后续再进前台,不会再
onCreate(),只会触发onNewWant()+onForeground()。
2.2 场景二:通过 startAbilityByCall() 启动到后台
这个是比较"特别"的情况: 开发者通过 UIAbilityContext.startAbilityByCall() 把一个 UIAbility 启动在后台,一开始并不会显示 UI。
流程大概是:
-
启动到后台
-
onCreate() -
onBackground()
注意:这里 不会执行
onWindowStageCreate(),因为窗口还没建。 -
-
后面再把它拉到前台
onNewWant()onWindowStageCreate()(此时才创建窗口并加载 UI)onForeground()
这种模式适合那种:一开始先在后台准备数据,后面才需要 UI 界面的场景。
3. 每个生命周期回调适合做什么?
下面我按自己写代码时的习惯,把每个回调"怎么用"总结了一遍。
3.1 onCreate():只会执行一次的初始化
触发时机:
- UIAbility 实例第一次创建的时候
适合做的事:
-
整个生命周期只需要做一次的初始化:
- 全局配置
- 轻量的依赖初始化
- 日志系统 / 埋点初始化(如果不放在 Application 里)
- 初始化状态数据、单例注入等
示例:
scala
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 只做"一次性"的初始化
console.info('[EntryAbility] onCreate');
}
}
3.2 onWindowStageCreate():窗口准备好,加载 UI + 订阅窗口事件
触发时机:
- UIAbility 实例创建之后
- 进入前台之前
- WindowStage 创建完成时
适合做的事:
-
调用
windowStage.loadContent('pages/Index')加载页面 -
订阅窗口事件,比如:
- 前台 / 后台(
SHOWN/HIDDEN) - 获焦 / 失焦(
ACTIVE/INACTIVE) - 可交互 / 不可交互(
RESUMED/PAUSED)
- 前台 / 后台(
示例(精简版):
javascript
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
// 订阅窗口事件
windowStage.on('windowStageEvent', (event) => {
switch (event) {
case window.WindowStageEventType.SHOWN:
console.info('WindowStage 前台');
break;
case window.WindowStageEventType.HIDDEN:
console.info('WindowStage 后台');
break;
default:
break;
}
});
// 加载首页 UI
windowStage.loadContent('pages/Index', () => {
console.info('Index 页面加载完成');
});
}
}
3.3 onForeground():进入前台,适合"重新占用资源"
触发时机:
- UIAbility 即将进入前台、UI 即将可见 / 可交互之前
适合做的事:
-
重新获取或启用前台才需要的资源:
- 开启定位、传感器
- 恢复相机预览
- 重新注册某些前台监听
示例:
scala
export default class EntryAbility extends UIAbility {
onForeground(): void {
// 比如重新打开定位、相机、前台服务等
console.info('[EntryAbility] onForeground');
}
}
3.4 onBackground():进入后台,释放不必要的前台资源
触发时机:
- 当 UI 完全不可见后
适合做的事:
-
停掉前台才需要的资源:
- 停止定位
- 关闭相机预览
- 取消部分前台网络轮询
-
但不要做特别耗时的操作(比如大批量存盘、数据库大事务)
示例:
scala
export default class EntryAbility extends UIAbility {
onBackground(): void {
// 释放 UI 不可见时可以停掉的资源
console.info('[EntryAbility] onBackground');
}
}
小提示:这个回调时间是很短的,更多是"关资源",不是"干重活"。
3.5 onWindowStageWillDestroy():窗口将销毁,还能操作 WindowStage
触发时机:
- UIAbility 实例销毁之前
- WindowStage 即将销毁,此时 WindowStage 仍然可用
适合做的事:
-
和
WindowStage相关的收尾工作:- 取消事件订阅(
windowStage.off('windowStageEvent')) - 释放由 WindowStage 创建的相关资源
- 取消事件订阅(
示例(重点是取消订阅):
typescript
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
private windowStage?: window.WindowStage;
onWindowStageCreate(windowStage: window.WindowStage): void {
this.windowStage = windowStage;
// 订阅事件...
}
onWindowStageWillDestroy(windowStage: window.WindowStage): void {
if (this.windowStage) {
this.windowStage.off('windowStageEvent');
}
console.info('[EntryAbility] onWindowStageWillDestroy');
}
}
3.6 onWindowStageDestroy():窗口已经销毁,用来收尾 UI 资源
触发时机:
- UIAbility 实例销毁前
- WindowStage 已经销毁,不能再用它访问窗口
适合做的事:
-
释放 UI 相关资源:
- 清空某些 UI 层面的缓存
- 重置 UI 状态(如果有必要)
示例:
scala
export default class EntryAbility extends UIAbility {
onWindowStageDestroy(): void {
// UI 资源收尾
console.info('[EntryAbility] onWindowStageDestroy');
}
}
3.7 onDestroy():真正的"临终回调"
触发时机:
- UIAbility 实例要被销毁前的最后一个生命周期回调
比如:
- 你调用
terminateSelf()主动结束当前 UIAbility 时; - 某些场景下系统清理时(注意:并不是所有清理都会走 onDestroy,见下面说明)。
适合做的事:
- 释放系统资源、断开连接;
- 持久化业务数据(注意不要太慢);
- 做一些"善后"的日志记录。
注意几点:
-
从 API 13 开始:
- 无实况窗 的应用:用户在最近任务中"一键清理"时,进程可能直接被杀死,不触发
onDestroy(); - 有实况窗的应用:仍然会走
onDestroy()。
- 无实况窗 的应用:用户在最近任务中"一键清理"时,进程可能直接被杀死,不触发
-
调试时,从最近任务里划掉调试应用的某个任务,也可能直接杀进程,不走
onDestroy()。
示例:
scala
export default class EntryAbility extends UIAbility {
onDestroy(): void {
// 释放资源、保存数据等
console.info('[EntryAbility] onDestroy');
}
}
3.8 onNewWant():已存在实例再次被启动时
触发时机:
- UIAbility 实例已经存在,再次调用启动它时 (比如单实例模式下,从其他地方再次
startAbility这个 UIAbility)
适合做的事:
-
根据新的
Want更新页面要展示的内容:- 比如:从通知栏点进来,要跳到某个聊天窗口 / 详情页;
- 或者:根据新的参数刷新数据。
示例:
scala
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 例如更新当前要展示的内容
console.info('[EntryAbility] onNewWant, params: ' + JSON.stringify(want.parameters));
}
}
4. 如何"监听别的 UIAbility 的生命周期"?
有时候我们不只关心当前 Ability,还想从应用层面统一监听 UIAbility 生命周期变化,官方也提供了能力:
- 可以通过
ApplicationContext注册监听 UIAbility 生命周期事件。
这一块可以单独写一篇"如何用 ApplicationContext 监听 UIAbility 生命周期"的笔记,这里先留个坑。
5. 我自己的使用习惯小总结
我现在写 Stage 模型的 UIAbility,大概会按这个习惯来:
- 一次性的初始化(全局级) →
onCreate() - UI 框架 & Window 设置 →
onWindowStageCreate() - 开资源(定位、传感器、订阅前台事件等) →
onForeground() - 关资源(停止定位、停止前台轮询等) →
onBackground() - 取消窗口事件订阅 / Window 相关清理 →
onWindowStageWillDestroy() - UI 资源收尾 →
onWindowStageDestroy() - 业务级的"最后收尾"和数据持久化 →
onDestroy() - 单实例重复启动时更新参数 / 跳转状态 →
onNewWant()