Harmony学习之应用生命周期管理
Harmony学习之应用生命周期管理
一、场景引入
小明在上一篇文章中完成了登录跳转功能,现在他需要确保应用在不同状态下(前台、后台、销毁)能够正确管理资源。比如用户从登录页切换到其他应用时,需要暂停网络请求;应用从后台返回时,需要刷新用户数据;应用销毁时,需要清理定时器和缓存。本篇文章将系统讲解HarmonyOS的应用生命周期管理,帮助小明实现资源的合理分配和释放。
二、生命周期体系总览
HarmonyOS 5 API 12+的生命周期体系采用多层次结构,涵盖从应用启动到销毁的完整流程:
| 层级 | 核心作用 | 典型场景 |
|---|---|---|
| Application | 应用全局上下文管理 | 初始化全局服务、注册崩溃监控 |
| UIAbility | 功能单元的生命周期管理 | 首页Ability加载用户资产数据 |
| 页面(@Entry) | 页面级UI展示与交互 | 转账页面显示时刷新余额 |
| 组件(@Component) | 独立UI单元的渲染与资源释放 | 行情组件销毁时取消数据订阅 |
三、Application生命周期
Application是应用的全局上下文,管理所有Ability共享的资源,生命周期贯穿应用从启动到销毁的全流程。
1. 核心生命周期方法
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
import { EncryptUtil } from '../common/EncryptUtil'; // 加密工具类
export default class EntryAbility extends UIAbility {
// 1. Ability创建时触发
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
console.log('Ability创建:初始化全局状态');
// 金融场景:解密并加载本地存储的用户Token
EncryptUtil.decryptUserToken();
// 初始化全局服务
this.initGlobalServices();
}
// 2. 窗口舞台创建时触发
onWindowStageCreate(windowStage: window.WindowStage) {
console.log('窗口舞台创建:加载首页UI');
// 必须在此回调中加载UI页面
windowStage.loadContent('pages/Index', (err, data) => {
if (err) {
console.error('加载页面失败:', err);
return;
}
console.log('页面加载成功');
});
// 配置窗口属性
windowStage.getMainWindow((err, mainWindow) => {
if (err) {
console.error('获取主窗口失败:', err);
return;
}
// 设置窗口背景色
mainWindow.setWindowBackgroundColor('#FFFFFF');
});
}
// 3. Ability进入前台时触发
onForeground() {
console.log('Ability回到前台:恢复服务');
// 恢复在后台时暂停的操作
this.resumeServices();
}
// 4. Ability进入后台时触发
onBackground() {
console.log('Ability进入后台:暂停服务');
// 释放非必要资源,降低内存占用
this.releaseResources();
}
// 5. 窗口舞台销毁时触发
onWindowStageDestroy() {
console.log('窗口舞台销毁:清理UI资源');
// 释放窗口相关资源
this.cleanupWindowResources();
}
// 6. Ability销毁时触发
onDestroy() {
console.log('Ability销毁:释放所有资源');
// 清理全局资源
this.cleanupGlobalResources();
}
// 7. 系统配置变化时触发(如屏幕旋转)
onConfigurationUpdated(config: Configuration) {
console.log('系统配置变化:适配新配置');
// 适配横竖屏布局
this.adaptLayout(config);
}
// 8. 系统内存不足时触发
onTrimMemory(level: number) {
console.log('系统内存不足:释放非核心资源');
// 根据紧急程度释放资源
this.releaseMemory(level);
}
}
2. 生命周期方法详解
| 生命周期方法 | 触发时机 | 典型用途 |
|---|---|---|
onCreate() |
Ability首次创建时 | 初始化Ability级资源、获取上下文 |
onWindowStageCreate() |
窗口舞台创建时 | 加载UI页面、设置窗口属性 |
onForeground() |
Ability从后台回到前台时 | 恢复网络连接、刷新数据 |
onBackground() |
Ability进入后台时 | 暂停网络请求、释放资源 |
onWindowStageDestroy() |
窗口舞台销毁时 | 清理UI相关资源 |
onDestroy() |
Ability销毁时 | 释放所有资源、保存数据 |
onConfigurationUpdated() |
系统配置变化时 | 适配横竖屏、语言切换 |
onTrimMemory() |
系统内存不足时 | 释放非核心资源 |
四、页面生命周期
页面是被@Entry装饰的特殊组件,继承组件生命周期的同时,新增页面级交互相关函数。
1. 页面生命周期方法
@Entry
@Component
struct HomePage {
@State userBalance: number = 0;
private timerId: number = -1;
// 1. 组件即将显示时触发(在build()之前)
aboutToAppear() {
console.log('页面即将显示:初始化数据');
// 加载页面数据
this.loadUserData();
}
// 2. 页面每次显示时触发
onPageShow() {
console.log('页面显示:刷新实时数据');
// 启动定时器刷新数据
this.startDataRefresh();
}
// 3. 页面每次隐藏时触发
onPageHide() {
console.log('页面隐藏:暂停操作');
// 停止定时器
this.stopDataRefresh();
}
// 4. 组件即将销毁时触发
aboutToDisappear() {
console.log('页面即将销毁:清理资源');
// 清理定时器、解绑事件
this.cleanup();
}
// 5. build()执行完毕后触发(API 12新增)
onDidBuild() {
console.log('页面构建完成:初始化UI');
// 不建议在此修改状态变量
this.initUI();
}
// 6. 用户点击返回按钮时触发
onBackPress(): boolean {
console.log('返回按钮被点击');
// 返回true表示拦截返回,false表示允许返回
return this.confirmExit();
}
build() {
Column({ space: 20 }) {
Text('我的资产')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text(`总资产:${this.userBalance.toFixed(2)}元`)
.fontSize(18)
}
.width('100%')
.padding(16)
}
// 模拟数据加载
private loadUserData() {
// 实际场景:调用API获取用户数据
this.userBalance = 50000;
}
// 启动数据刷新定时器
private startDataRefresh() {
this.timerId = setInterval(() => {
// 模拟数据变化
this.userBalance += Math.random() * 100 - 50;
}, 5000);
}
// 停止数据刷新
private stopDataRefresh() {
if (this.timerId !== -1) {
clearInterval(this.timerId);
this.timerId = -1;
}
}
// 清理资源
private cleanup() {
this.stopDataRefresh();
}
// 确认退出
private confirmExit(): boolean {
// 实际场景:检查是否有未保存的数据
return false; // 允许返回
}
}
2. 页面生命周期方法对比
| 方法 | 触发时机 | 执行次数 | 典型用途 |
|---|---|---|---|
aboutToAppear() |
组件首次创建时 | 1次 | 初始化数据、订阅事件 |
onPageShow() |
页面每次显示时 | 多次 | 刷新实时数据、启动动画 |
onPageHide() |
页面每次隐藏时 | 多次 | 暂停操作、保存状态 |
aboutToDisappear() |
组件即将销毁时 | 1次 | 清理定时器、解绑事件 |
onDidBuild() |
build()执行完毕后 | 1次 | 初始化UI、数据上报 |
onBackPress() |
点击返回按钮时 | 多次 | 拦截返回、确认操作 |
五、组件生命周期
普通组件(@Component装饰)的生命周期相对简单,主要关注组件的创建和销毁。
1. 组件生命周期方法
@Component
struct MarketCard {
@State price: number = 0;
private timerId: number = -1;
build() {
Column() {
Text(`实时金价:${this.price.toFixed(2)}元/g`)
.fontSize(16)
.padding(10)
}
.backgroundColor('#f5f5f5')
.borderRadius(8)
}
// 组件即将显示时触发
aboutToAppear() {
console.log('行情卡片:开始监听实时价格');
this.startPriceRefresh();
}
// 组件即将销毁时触发
aboutToDisappear() {
console.log('行情卡片:即将销毁,准备清理资源');
this.stopPriceRefresh();
}
// build()执行完毕后触发
onDidBuild() {
console.log('行情卡片:构建完成');
// 不建议在此修改状态变量
}
// 启动价格刷新定时器
private startPriceRefresh() {
this.timerId = setInterval(() => {
this.price += Math.random() * 2 - 1; // 模拟价格波动
}, 3000);
}
// 停止价格刷新
private stopPriceRefresh() {
if (this.timerId !== -1) {
clearInterval(this.timerId);
this.timerId = -1;
}
}
}
2. 组件生命周期方法对比
| 方法 | 触发时机 | 执行次数 | 典型用途 |
|---|---|---|---|
aboutToAppear() |
组件首次创建时 | 1次 | 初始化数据、启动定时器 |
aboutToDisappear() |
组件即将销毁时 | 1次 | 清理定时器、解绑事件 |
onDidBuild() |
build()执行完毕后 | 1次 | 初始化UI、数据上报 |
六、生命周期调用顺序
1. 应用启动流程
App进程启动
↓
Application.onCreate() → 初始化全局服务
↓
UIAbility.onCreate() → 初始化Ability级资源
↓
UIAbility.onWindowStageCreate() → 加载UI页面
↓
UIAbility.onForeground() → 应用进入前台
↓
页面.aboutToAppear() → 页面即将显示
↓
页面.build() → 构建UI结构
↓
页面.onDidBuild() → build执行完毕
↓
页面.onPageShow() → 页面显示
2. 应用进入后台
用户切换到其他应用
↓
页面.onPageHide() → 页面隐藏
↓
UIAbility.onBackground() → 应用进入后台
3. 应用返回前台
用户切回应用
↓
UIAbility.onForeground() → 应用回到前台
↓
页面.onPageShow() → 页面显示
4. 应用销毁流程
用户退出应用
↓
页面.onPageHide() → 页面隐藏
↓
页面.aboutToDisappear() → 页面即将销毁
↓
UIAbility.onWindowStageDestroy() → 窗口舞台销毁
↓
UIAbility.onDestroy() → Ability销毁
↓
Application.onDestroy() → 应用销毁
七、实战案例:登录状态管理
下面是一个完整的登录状态管理示例,综合运用了各个层级的生命周期管理:
1. Application层全局状态管理
// src/main/ets/Application.ts
import { Application } from '@ohos.app.ability.Application';
import { GlobalStateManager } from './common/GlobalStateManager';
export default class MyApplication extends Application {
onCreate() {
console.log('应用启动:初始化全局状态');
// 初始化全局状态管理器
GlobalStateManager.getInstance().init();
// 注册崩溃监控
this.registerCrashMonitor();
}
onDestroy() {
console.log('应用销毁:清理全局资源');
// 清理全局资源
GlobalStateManager.getInstance().cleanup();
}
private registerCrashMonitor() {
// 实际场景:注册崩溃监控服务
}
}
2. UIAbility层登录状态管理
// src/main/ets/entryability/EntryAbility.ts
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
import { UserManager } from '../common/UserManager';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
console.log('Ability创建:初始化用户状态');
// 检查用户登录状态
const isLoggedIn = UserManager.getInstance().isLoggedIn();
if (isLoggedIn) {
// 已登录,直接跳转到首页
this.navigateToHome();
} else {
// 未登录,跳转到登录页
this.navigateToLogin();
}
}
onWindowStageCreate(windowStage: window.WindowStage) {
console.log('窗口舞台创建:加载UI页面');
// 根据登录状态加载不同页面
const isLoggedIn = UserManager.getInstance().isLoggedIn();
const targetPage = isLoggedIn ? 'pages/Home' : 'pages/Login';
windowStage.loadContent(targetPage, (err, data) => {
if (err) {
console.error('加载页面失败:', err);
return;
}
console.log('页面加载成功');
});
}
onForeground() {
console.log('Ability回到前台:验证登录状态');
// 检查登录状态是否过期
this.checkLoginStatus();
}
onBackground() {
console.log('Ability进入后台:保存用户数据');
// 保存用户数据到本地
UserManager.getInstance().saveUserData();
}
onDestroy() {
console.log('Ability销毁:清理资源');
// 清理资源
UserManager.getInstance().cleanup();
}
private navigateToHome() {
// 实际场景:跳转到首页
}
private navigateToLogin() {
// 实际场景:跳转到登录页
}
private checkLoginStatus() {
// 实际场景:检查登录状态是否过期
const isExpired = UserManager.getInstance().isTokenExpired();
if (isExpired) {
// 登录过期,跳转到登录页
this.navigateToLogin();
}
}
}
3. 页面层数据管理
// src/main/ets/pages/Home.ets
import router from '@ohos.router';
import { UserManager } from '../common/UserManager';
@Entry
@Component
struct Home {
@State userInfo: any = {};
@State balance: number = 0;
private dataRefreshTimer: number = -1;
aboutToAppear() {
console.log('首页即将显示:加载用户数据');
// 加载用户信息
this.loadUserInfo();
}
onPageShow() {
console.log('首页显示:启动数据刷新');
// 启动定时器刷新数据
this.startDataRefresh();
}
onPageHide() {
console.log('首页隐藏:停止数据刷新');
// 停止定时器
this.stopDataRefresh();
}
aboutToDisappear() {
console.log('首页即将销毁:清理资源');
// 清理资源
this.cleanup();
}
onBackPress(): boolean {
console.log('返回按钮被点击');
// 确认退出应用
promptAction.showDialog({
title: '确认退出',
message: '确定要退出应用吗?',
buttons: [
{ text: '取消', color: '#666666' },
{ text: '确定', color: '#FF3B30' }
]
}).then((result) => {
if (result.index === 1) {
// 确定退出
this.exitApp();
}
});
return true; // 拦截默认返回行为
}
build() {
Column({ space: 20 }) {
Text(`欢迎回来,${this.userInfo.name || '用户'}`)
.fontSize(24)
.fontWeight(FontWeight.Bold)
Text(`账户余额: ${this.balance.toFixed(2)}元`)
.fontSize(18)
Button('退出登录')
.width(200)
.onClick(() => {
this.logout();
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
// 加载用户信息
private loadUserInfo() {
const userInfo = UserManager.getInstance().getUserInfo();
this.userInfo = userInfo;
this.balance = userInfo.balance || 0;
}
// 启动数据刷新定时器
private startDataRefresh() {
this.dataRefreshTimer = setInterval(() => {
// 模拟数据刷新
this.balance += Math.random() * 10 - 5;
}, 10000);
}
// 停止数据刷新
private stopDataRefresh() {
if (this.dataRefreshTimer !== -1) {
clearInterval(this.dataRefreshTimer);
this.dataRefreshTimer = -1;
}
}
// 清理资源
private cleanup() {
this.stopDataRefresh();
}
// 退出登录
private logout() {
promptAction.showDialog({
title: '确认退出登录',
message: '确定要退出登录吗?',
buttons: [
{ text: '取消', color: '#666666' },
{ text: '确定', color: '#FF3B30' }
]
}).then((result) => {
if (result.index === 1) {
// 清除登录状态
UserManager.getInstance().logout();
// 跳转到登录页
router.replaceUrl({
url: 'pages/Login'
});
}
});
}
// 退出应用
private exitApp() {
// 实际场景:退出应用
AppControl.terminate();
}
}
八、最佳实践与注意事项
1. 生命周期方法使用建议
| 生命周期方法 | 推荐操作 | 避免操作 |
|---|---|---|
onCreate() |
初始化全局配置、获取上下文 | 执行耗时操作、加载UI |
onWindowStageCreate() |
加载UI页面、设置窗口属性 | 执行耗时网络请求 |
onForeground() |
恢复网络连接、刷新数据 | 执行耗时操作 |
onBackground() |
暂停网络请求、释放资源 | 执行耗时操作 |
aboutToAppear() |
初始化页面数据、订阅事件 | 执行耗时操作 |
onPageShow() |
刷新实时数据、启动动画 | 执行耗时操作 |
onPageHide() |
暂停操作、保存状态 | 执行耗时操作 |
aboutToDisappear() |
清理定时器、解绑事件 | 修改状态变量 |
2. 性能优化建议
避免在生命周期方法中执行耗时操作:
// ❌ 不推荐:在生命周期方法中执行耗时操作
aboutToAppear() {
// 耗时网络请求
this.fetchDataFromServer(); // 可能导致页面卡顿
}
// ✅ 推荐:使用异步任务
aboutToAppear() {
// 启动异步任务
TaskPool.execute(async () => {
const data = await this.fetchDataFromServer();
// 更新UI
this.updateUI(data);
});
}
合理释放资源:
onBackground() {
// 释放非必要资源
this.releaseMemory();
// 保存用户数据
this.saveUserData();
}
aboutToDisappear() {
// 清理定时器
this.cleanupTimers();
// 解绑事件监听
this.unbindEvents();
}
3. 常见问题与解决方案
问题1:内存泄漏
// ❌ 错误:未清理定时器
aboutToAppear() {
this.timerId = setInterval(() => {
// 定时任务
}, 1000);
}
// ✅ 正确:在aboutToDisappear中清理
aboutToDisappear() {
if (this.timerId !== -1) {
clearInterval(this.timerId);
this.timerId = -1;
}
}
问题2:状态不一致
// ❌ 错误:在onPageHide中修改状态
onPageHide() {
this.userInfo = null; // 可能导致状态不一致
}
// ✅ 正确:在aboutToDisappear中清理
aboutToDisappear() {
this.userInfo = null;
}
问题3:网络请求未取消
// ❌ 错误:未取消网络请求
aboutToAppear() {
this.requestId = http.request({
// 请求配置
});
}
// ✅ 正确:在aboutToDisappear中取消请求
aboutToDisappear() {
if (this.requestId) {
http.cancelRequest(this.requestId);
this.requestId = undefined;
}
}
九、总结与行动建议
核心要点回顾
- 生命周期体系:掌握Application、UIAbility、页面、组件四个层级的生命周期管理
- 核心方法:理解
onCreate、onWindowStageCreate、onForeground、onBackground、onDestroy等核心生命周期方法 - 页面生命周期:掌握
aboutToAppear、onPageShow、onPageHide、aboutToDisappear、onBackPress等页面级方法 - 组件生命周期:掌握
aboutToAppear、aboutToDisappear、onDidBuild等组件级方法 - 调用顺序:理解应用启动、前后台切换、应用销毁时的生命周期调用顺序
行动建议
- 动手实践:按照本文示例,完成登录状态管理的完整实现
- 生命周期调试:在生命周期方法中添加日志,观察调用顺序和时机
- 性能优化:检查现有代码,确保在合适的生命周期方法中执行相应操作
- 资源管理:确保定时器、网络请求、事件监听等资源得到正确释放
- 状态管理:合理使用
@State、@Prop、@Link装饰器管理组件状态
通过本篇文章的学习,你已经掌握了HarmonyOS应用生命周期管理的核心能力。下一篇文章将深入讲解网络请求与数据获取,帮助你实现从服务器获取数据并展示在界面上。

浙公网安备 33010602011771号