HarmonyOS7 生命周期:UIAbility 4 个关键回调你一定要搞懂
文章目录
前言
生命周期回调不是随便写的,每个回调代表应用处于不同状态,搞混了代码逻辑就全乱。
我见过最多的低级 bug 之一:在 onCreate 里初始化数据库,结果切到后台再回来,数据库又初始化了一遍,数据全乱了。同学,你压根没搞懂 UIAbility 的生命周期啊。

UIAbility 是 HarmonyOS7 应用的基本单元——你可以理解为 Android 的 Activity,但粒度更大。一个应用可以有多个 UIAbility,每个对应最近任务列表里的一条记录。

系统在调度 UIAbility 的时候,会依次调用几个生命周期回调。你的代码写在哪个回调里,直接决定了它的执行时机。 写错位置,轻则重复执行,重则数据丢失。今天把这 4 个关键回调掰开了讲。
UIAbility 是什么
一句话:UIAbility 是系统调度的基本单元,提供窗口让 UI 渲染。
所有页面和组件要显示,必须依托一个窗口。UIAbility 就是创建窗口的那个"壳"——你写的 @Entry 页面,都是通过 UIAbility 的 windowStage.loadContent() 加载进去的。
一个 UIAbility 可以管理多个页面(通过路由跳转),也可以只有单个页面。具体怎么拆分看业务需要。
4 个关键回调详解
UIAbility 的生命周期回调有 6 个,但最核心的是这 4 个:
onCreate → onWindowStageCreate → onForeground → onBackground
↕
(可反复切换)
加上销毁阶段的 onWindowStageDestroy 和 onDestroy,一共 6 个。重点看前 4 个。
onCreate:应用启动,初始化就放这
系统创建 UIAbility 实例时触发,整个生命周期只调一次。
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
console.info('onCreate: 应用启动')
// 读取启动参数
let param = want.parameters?.['userId'] as string
console.info(`启动参数: ${param}`)
// 初始化全局资源(数据库连接、网络配置等)
AppStorage.setOrCreate('globalConfig', { theme: 'dark' })
}
}

关键代码讲解:
want参数 —— 启动时传进来的数据,别的 Ability 或系统拉起你时可以通过want.parameters传参launchParam—— 包含启动模式信息,可以判断是冷启动还是热启动AppStorage.setOrCreate()—— 在这里设置全局数据,所有页面都能访问
血泪教训:只放一次性初始化逻辑,别把每次切回前台都要执行的代码放这里。
onCreate只跑一次,切后台再回来不会重新触发。
onWindowStageCreate:窗口创建,加载页面
onCreate 之后,系统创建窗口,触发这个回调。加载入口页面就在这里。
onWindowStageCreate(windowStage: window.WindowStage): void {
console.info('onWindowStageCreate: 窗口已创建')
// 设置窗口属性
windowStage.getMainWindow().then((win: window.Window) => {
win.setWindowLayoutFullScreen(true)
let sysBarProps: window.SystemBarProperties = {
statusBarColor: '#00000000',
statusBarContentColor: '#000000'
}
win.setWindowSystemBarProperties(sysBarProps)
})
// 加载入口页面
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
console.error(`页面加载失败: ${err.code}`)
return
}
console.info('页面加载成功')
})
}
关键代码讲解:
windowStage.getMainWindow()—— 获取主窗口对象,可以设置全屏、状态栏颜色等setWindowLayoutFullScreen(true)—— 设置沉浸式状态栏,页面内容延伸到状态栏区域windowStage.loadContent('pages/Index')—— 这行最关键,指定要加载的页面路径,路径对应pages/目录下的文件- 页面加载是异步的,回调里可以判断是否成功
很多开发者喜欢在这里初始化数据库,也可以,但注意这只执行一次,别重复初始化。
onForeground:切到前台,恢复状态
应用从后台切回前台时触发。用户看到的界面要刷新、暂停的任务要恢复,都在这里处理。
onForeground(): void {
console.info('onForeground: 切到前台')
// 恢复暂停的任务
this.resumeBackgroundTask()
// 刷新可能过期的数据
this.refreshDataIfNeeded()
// 通知所有页面恢复
AppStorage.setOrCreate('isForeground', true)
}
private resumeBackgroundTask(): void {
let taskInfo = AppStorage.get<string>('pausedTask')
if (taskInfo) {
console.info(`恢复任务: ${taskInfo}`)
}
}
private refreshDataIfNeeded(): void {
let lastUpdate = AppStorage.get<number>('lastUpdateTime') || 0
let now = Date.now()
if (now - lastUpdate > 30000) {
console.info('数据已过期,重新拉取')
AppStorage.setOrCreate('needRefresh', true)
}
}
关键代码讲解:
- 这个回调每次从后台回到前台都会触发,可以反复调用
AppStorage.setOrCreate('isForeground', true)—— 页面组件可以通过@StorageLink监听这个值,自动响应前后台切换- 数据过期检查 —— 应用在后台可能很久,回到前台时数据可能已经过时,需要判断是否刷新
这才是放"切回前台逻辑"的正确位置,不是 onCreate!
onBackground:切到后台,保存状态
用户按 Home 键、切到别的 App,应用进入后台,触发 onBackground。保存状态、暂停任务、释放资源,就在这里。
onBackground(): void {
console.info('onBackground: 切到后台')
// 保存当前状态
this.saveAppState()
// 暂停耗时操作
this.pauseOngoingTasks()
// 释放不必要的资源
this.releaseIdleResources()
AppStorage.setOrCreate('isForeground', false)
AppStorage.setOrCreate('lastUpdateTime', Date.now())
}
private saveAppState(): void {
let state = {
currentPage: 'DetailPage',
scrollPosition: 256,
formData: { name: '测试', age: 20 }
}
AppStorage.setOrCreate('appState', JSON.stringify(state))
}
private pauseOngoingTasks(): void {
console.info('暂停进行中的任务')
}
private releaseIdleResources(): void {
console.info('释放空闲资源')
}
关键代码讲解:
saveAppState()—— 把关键状态序列化存到 AppStorage,下次回来可以恢复- 切后台后进程随时可能被杀,重要数据必须在这里持久化,不能指望下次
onForeground还能恢复内存中的数据 - 释放资源 —— 比如关闭不必要的文件句柄、取消网络请求等,减少内存占用,降低被系统杀掉的概率
WindowStage 生命周期
WindowStage 也有自己的生命周期,夹在 UIAbility 生命周期之间:
onWindowStageCreate → onWindowStageDestroy
onWindowStageCreate:窗口创建时触发,在这里加载页面onWindowStageDestroy:窗口销毁时触发,在 UIAbility 销毁之前执行
如果你在 onWindowStageCreate 里做了资源分配(比如创建数据库连接),对应的清理逻辑应该放在 onWindowStageDestroy 里。
与 UI 生命周期关系
UIAbility 生命周期是宏观的,组件生命周期是微观的。它们的关系:
UIAbility.onCreate
│
UIAbility.onWindowStageCreate
│
▼
页面 aboutToAppear ←── 组件 aboutToAppear
│
▼
页面 onPageShow ←── 用户可见
│
▼
UIAbility.onForeground
│
─ ─ ─ 用户使用中 ─ ─ ─
│
UIAbility.onBackground
│
▼
页面 onPageHide ←── 用户不可见
│
▼
UIAbility.onWindowStageDestroy
│
▼
UIAbility.onDestroy
│
▼
页面 aboutToDisappear ←── 组件 aboutToDisappear
关键理解:UIAbility 生命周期管理的是进程级别的事,组件生命周期管理的是 UI 级别的事。 别搞混了。
实战:页面状态保存
最常见的场景:用户在详情页滑到一半,切到别的 App,回来后页面位置丢了。用生命周期回调来保存和恢复:
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
AppStorage.setOrCreate('scrollOffset', 0)
AppStorage.setOrCreate('currentRoute', 'Index')
}
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index')
}
onForeground(): void {
let savedOffset = AppStorage.get<number>('scrollOffset') || 0
if (savedOffset > 0) {
AppStorage.setOrCreate('restoreScroll', true)
}
}
onBackground(): void {
AppStorage.setOrCreate('isForeground', false)
AppStorage.setOrCreate('lastBackgroundTime', Date.now())
}
}
页面侧配合恢复:
@Entry
@Component
struct DetailPage {
@StorageLink('scrollOffset') scrollOffset: number = 0
@StorageLink('restoreScroll') needRestore: boolean = false
private scroller: Scroller = new Scroller()
onPageShow(): void {
if (this.needRestore && this.scrollOffset > 0) {
setTimeout(() => {
this.scroller.scrollOffset(this.scrollOffset)
this.needRestore = false
}, 100)
}
}
onPageHide(): void {
this.scrollOffset = this.scroller.currentOffset().yOffset
}
build() {
Scroll(this.scroller) {
Column() {
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number) => {
Text(`第 ${item} 项内容`).height(120)
})
}
}
}
}
关键代码讲解:
onPageHide里保存滚动偏移量到AppStorage—— 切后台时页面先隐藏,这是最后的保存机会onForeground里设置restoreScroll标记 —— 通知页面需要恢复滚动位置onPageShow里执行恢复 —— 页面重新可见时,根据标记和保存的偏移量滚动回去setTimeout延迟 100ms —— 等页面渲染完再滚动,否则可能还没布局好就跳了
写在最后
UIAbility 生命周期就一句话:onCreate 初始化一次,onForeground 恢复状态,onBackground 保存状态,别搞混。
最常犯的错误就是把本该放在 onForeground 的逻辑写到了 onCreate,结果冷启动正常、热启动出 bug。记住 onCreate 只调一次,前后台切换不会重新触发——这点搞明白了,生命周期的坑就踩得差不多了。
更多推荐



所有评论(0)