
前言
欢迎阅读《HarmonyOS 应用开发实战》系列文章。本系列基于开源项目 "海风日记"(一款 HarmonyOS 原生日记 App)的完整源码,深入剖析 ArkUI 组件、Kit 能力与鸿蒙特性在真实项目中的落地实践。
UIAbility 是 HarmonyOS Stage 模型下应用能力的核心入口,理解其生命周期是开发鸿蒙应用的第一步。本文将结合"海风日记"的 EntryAbility.ets 源码,详细讲解 UIAbility 的各个生命周期回调、窗口管理以及实际开发中的最佳实践。
一、UIAbility 概述
1.1 什么是 UIAbility
UIAbility 是 HarmonyOS Stage 模型中应用能力的抽象基类 ,它替代了 FA 模型中的 Ability,提供了更清晰的生命周期管理和窗口管理能力。每个 UIAbility 对应一个独立的应用窗口,可以理解为用户可见的一个"页面容器"。
1.2 Stage 模型 vs FA 模型
在 HarmonyOS 的发展历程中,Stage 模型是推荐的应用开发模型,相比旧的 FA 模型,它有以下优势:
| 特性 | FA 模型 | Stage 模型 |
|---|---|---|
| 生命周期 | 分散在多个回调 | 统一在 UIAbility 中管理 |
| 窗口管理 | 通过 Context 间接操作 | 通过 WindowStage 直接管理 |
| 组件化 | 能力较弱 | 支持多 HAP 和 HSP 共享包 |
| 后台任务 | 支持有限 | 提供 WorkScheduler 等标准 API |
| 推荐程度 | 兼容保留 | 官方推荐 |
1.3 UIAbility 的核心职责
UIAbility 承担了以下关键职责:
- 生命周期管理:管理应用的创建、启动、前后台切换、销毁
- 窗口管理:创建和管理应用窗口,包括状态栏、导航栏等
- 页面加载:通过 WindowStage 加载首屏页面
- Ability 间通信:支持 Want 隐式/显式启动
- 配置管理:读取 module.json5 中的模块配置
提示 :每个 Entry 类型的 HAP 模块只能有一个 EntryAbility,且必须在 module.json5 中配置
mainElement字段。
二、海风日记的 EntryAbility 源码分析
2.1 完整源码
"海风日记"的入口能力定义在 entryability/EntryAbility.ets 中,代码如下:
typescript
import { UIAbility, Want, AbilityConstant } from '@kit.AbilityKit'
import { window } from '@kit.ArkUI'
import { hilog } from '@kit.PerformanceAnalysisKit'
const TAG = 'EntryAbility'
const DOMAIN = 0xFF00
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, TAG, '海风日记 onCreate')
}
onDestroy(): void {
hilog.info(DOMAIN, TAG, 'onDestroy')
}
onWindowStageCreate(windowStage: window.WindowStage): void {
hilog.info(DOMAIN, TAG, 'onWindowStageCreate')
windowStage.loadContent('pages/SplashPage', (err) => {
if (err.code !== 0) {
hilog.error(DOMAIN, TAG, `loadContent failed: ${JSON.stringify(err)}`)
return
}
hilog.info(DOMAIN, TAG, 'loadContent success')
})
windowStage.getMainWindow().then((win) => {
win.setWindowSystemBarProperties({
statusBarColor: '#00000000',
statusBarContentColor: '#2D2926'
})
})
}
onWindowStageDestroy(): void {}
onForeground(): void {}
onBackground(): void {}
}
2.2 代码结构分析
这段代码虽然简短,但包含了 UIAbility 的核心生命周期回调,我们可以将其拆解为以下几个部分:
| 回调方法 | 触发时机 | 典型用途 |
|---|---|---|
onCreate |
Ability 首次创建时 | 初始化数据、日志埋点 |
onDestroy |
Ability 销毁时 | 释放资源、保存状态 |
onWindowStageCreate |
窗口阶段创建时 | 加载首屏页面、配置窗口 |
onWindowStageDestroy |
窗口阶段销毁时 | 清理窗口相关资源 |
onForeground |
Ability 进入前台时 | 恢复 UI 状态 |
onBackground |
Ability 进入后台时 | 保存临时数据 |
三、生命周期详解
3.1 onCreate:Ability 的创建入口
onCreate 在 Ability 首次创建时被调用,是整个应用生命周期的起点。在"海风日记"中,我们在此处记录日志:
typescript
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, TAG, '海风日记 onCreate')
}
onCreate 接收两个参数:
want:启动该 Ability 的请求信息,包含bundleName、abilityName、uri、parameters等launchParam:启动参数,包含launchReason(启动原因)、lastExitReason(上次退出原因)等
提示 :
onCreate中不应执行耗时操作,否则会影响应用启动速度。建议将数据初始化 、依赖注入 等操作放在此处,而页面渲染 相关的操作放在onWindowStageCreate中。
3.2 onDestroy:Ability 的销毁清理
当 Ability 被销毁时,onDestroy 被调用。注意 :这不是用户关闭应用时一定触发的回调,系统可能会在后台直接杀死进程而不调用 onDestroy。
typescript
onDestroy(): void {
hilog.info(DOMAIN, TAG, 'onDestroy')
}
onDestroy 适合做以下操作:
- 释放数据库连接
- 取消订阅的事件
- 停止后台任务
- 保存关键数据到持久化存储
3.3 onWindowStageCreate:窗口创建与首屏加载
这是最关键的生命周期回调。当 UIAbility 的窗口阶段创建完成后,系统会回调此方法,我们可以在此处加载首屏页面和配置窗口属性。
typescript
onWindowStageCreate(windowStage: window.WindowStage): void {
hilog.info(DOMAIN, TAG, 'onWindowStageCreate')
// 第一步:加载首屏页面
windowStage.loadContent('pages/SplashPage', (err) => {
if (err.code !== 0) {
hilog.error(DOMAIN, TAG, `loadContent failed: ${JSON.stringify(err)}`)
return
}
hilog.info(DOMAIN, TAG, 'loadContent success')
})
// 第二步:配置窗口属性
windowStage.getMainWindow().then((win) => {
win.setWindowSystemBarProperties({
statusBarColor: '#00000000', // 透明状态栏
statusBarContentColor: '#2D2926' // 状态栏文字颜色
})
})
}
loadContent 方法用于加载指定路径的页面作为首屏。路径配置在 main_pages.json 中:
json
{
"src": [
"pages/SplashPage",
"pages/Index",
"pages/onboarding/OnboardingPage"
]
}
3.4 onForeground 与 onBackground:前后台切换
当应用在前台和后台之间切换时,这两个回调被触发:
typescript
onForeground(): void {
// 应用进入前台:恢复 UI 更新、刷新数据
}
onBackground(): void {
// 应用进入后台:暂停动画、保存草稿
}
这两个回调的实际应用场景:
-
onForeground 适合做:
- 恢复动画播放
- 刷新数据列表
- 重新建立网络连接
-
onBackground 适合做:
- 暂停动画和计时器
- 自动保存日记草稿
- 释放内存资源
四、窗口管理实战
4.1 获取 MainWindow 对象
windowStage.getMainWindow() 返回一个 Promise,用于获取当前主窗口的引用:
typescript
windowStage.getMainWindow().then((win) => {
// win 是 MainWindow 实例
})
4.2 设置状态栏样式
"海风日记"通过 setWindowSystemBarProperties 方法设置状态栏为透明,并指定状态栏内容颜色:
typescript
win.setWindowSystemBarProperties({
statusBarColor: '#00000000', // 完全透明
statusBarContentColor: '#2D2926' // 暖棕黑文字
})
setWindowSystemBarProperties 支持的配置项:
| 属性 | 类型 | 说明 |
|---|---|---|
statusBarColor |
string | 状态栏背景色,#00000000 为透明 |
statusBarContentColor |
string | 状态栏内容颜色(时钟、电量等图标文字) |
navigationBarColor |
string | 导航栏背景色 |
navigationBarContentColor |
string | 导航栏按钮颜色 |
4.3 窗口其他配置
除了状态栏,MainWindow 还提供了丰富的配置接口:
typescript
// 设置窗口全屏
win.setWindowLayoutFullScreen(true)
// 设置窗口是否可调整大小
win.setWindowResizable(false)
// 设置窗口背景色
win.setWindowBackgroundColor('#FAFAF7')
// 获取窗口尺寸
win.getWindowProperties().windowRect
4.4 窗口管理的最佳实践
在实际开发中,窗口管理应遵循以下原则:
- 尽早配置 :在
onWindowStageCreate中尽早完成窗口配置,避免页面加载后出现视觉闪烁 - 状态栏适配:根据页面主题动态调整状态栏颜色,深色页面使用浅色状态栏文字
- 安全区域 :使用
expandSafeArea或 SafeArea 组件适配挖孔屏和圆角
五、日志系统集成
5.1 hilog 日志 API
"海风日记"使用 hilog(来自 @kit.PerformanceAnalysisKit)进行日志输出:
typescript
import { hilog } from '@kit.PerformanceAnalysisKit'
const TAG = 'EntryAbility'
const DOMAIN = 0xFF00
hilog.info(DOMAIN, TAG, '海风日记 onCreate')
hilog 的日志级别:
| 级别 | 方法 | 说明 |
|---|---|---|
| DEBUG | hilog.debug |
调试信息,仅在 DEBUG 版本输出 |
| INFO | hilog.info |
一般信息,记录关键事件 |
| WARN | hilog.warn |
警告信息,不影响功能的问题 |
| ERROR | hilog.error |
错误信息,影响功能的问题 |
| FATAL | hilog.fatal |
致命错误,会导致应用崩溃 |
5.2 DOMAIN 和 TAG 的作用
typescript
const DOMAIN = 0xFF00 // 应用自定义域标识
const TAG = 'EntryAbility' // 模块标签
- DOMAIN :取值范围
0x0~0xFFFF,用于区分不同应用的日志 - TAG:用于标识日志的来源模块,方便过滤
提示 :在大型项目中,建议为每个模块定义独立的 TAG,如
'HomeTab'、'DiaryDetail'等,便于日志定位问题。
5.3 日志查看工具
查看 hilog 输出的命令:
bash
# 查看所有日志
hilog
# 过滤特定 TAG
hilog | grep EntryAbility
# 过滤特定级别
hilog -t info
# 清除日志缓冲区
hilog -r
六、module.json5 配置详解
6.1 模块配置
UIAbility 的注册信息在 module.json5 中配置:
json5
{
"module": {
"name": "entry",
"type": "entry",
"mainElement": "EntryAbility",
"deviceTypes": ["phone"],
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:app_icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:app_icon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["action.system.home"]
}
]
}
]
}
}
6.2 关键配置项说明
| 配置项 | 说明 | 示例值 |
|---|---|---|
name |
Ability 名称,需与代码类名一致 | "EntryAbility" |
srcEntry |
源码入口路径 | "./ets/entryability/EntryAbility.ets" |
startWindowIcon |
启动窗口图标 | "$media:app_icon" |
startWindowBackground |
启动窗口背景色 | "$color:start_window_background" |
exported |
是否允许其他应用调用 | true |
skills |
意图过滤器,声明能处理的 Intent | 支持 home 入口 |
6.3 启动窗口配置
startWindowIcon 和 startWindowBackground 用于配置冷启动时的启动窗口(Splash Window),在应用的首帧渲染完毕前显示。这是一个重要的用户体验优化点:
- 建议将
startWindowBackground设置为应用的主题色或品牌色 - 避免使用纯白色作为启动背景,减少视觉突兀感
七、UIAbility 的完整生命周期时序图
UIAbility 的完整生命周期流转如下:
用户启动应用
↓
onCreate() ← 首次创建
↓
onWindowStageCreate() ← 窗口创建
↓
onForeground() ← 进入前台
↓
[应用运行中]
↓
用户按 Home 键 / 切到后台
↓
onBackground() ← 进入后台
↓
用户回到应用
↓
onForeground() ← 回到前台
↓
用户关闭应用
↓
onWindowStageDestroy() ← 窗口销毁
↓
onDestroy() ← Ability 销毁
7.1 异常场景处理
在实际开发中,还需要考虑以下异常场景:
- 进程被系统杀死 :
onDestroy可能不会被调用,需要依赖onBackground保存关键数据 - 配置变更 (如屏幕旋转):默认会销毁并重建 Ability,可通过
configChanges配置避免 - 多实例启动 :通过
launchType(singleton/standard/multiton)控制实例模式
7.2 各回调的触发次数
| 回调 | 触发次数 | 说明 |
|---|---|---|
onCreate |
整个生命周期1次 | 除非进程被杀死后重新启动 |
onForeground |
多次 | 每次回到前台触发 |
onBackground |
多次 | 每次进入后台触发 |
onDestroy |
整个生命周期1次 | 正常销毁时触发 |
八、常见问题与排查
8.1 loadContent 失败
如果 loadContent 返回错误码,可能的原因:
- 路径错误 :检查
main_pages.json中是否注册了该页面路径 - 页面组件未使用 @Entry 装饰 :每个页面必须使用
@Entry装饰 - 资源引用错误:检查页面中引用的字符串、颜色等资源是否存在
typescript
// 错误处理示例
windowStage.loadContent('pages/SplashPage', (err) => {
if (err.code !== 0) {
// 记录详细错误信息
hilog.error(DOMAIN, TAG, `loadContent failed: ${JSON.stringify(err)}`)
return
}
})
8.2 状态栏颜色不生效
检查以下几项:
- 是否在
onWindowStageCreate中尽早调用 statusBarColor是否使用 8 位色值(含 Alpha 通道)statusBarContentColor是否使用 6 位色值(不含 Alpha)
typescript
// 正确的配置方式
win.setWindowSystemBarProperties({
statusBarColor: '#00000000', // 8 位,含 Alpha
statusBarContentColor: '#2D2926' // 6 位,不含 Alpha
})
8.3 应用启动白屏
应用启动时出现短暂白屏,通常是因为启动窗口配置不当:
json5
{
"startWindowIcon": "$media:app_icon",
"startWindowBackground": "$color:start_window_background"
}
建议将 startWindowBackground 设置为应用的品牌主色 或页面背景色,与首屏页面颜色保持一致,减少视觉跳跃。
总结
本文从"海风日记"的 EntryAbility.ets 源码出发,深入剖析了 UIAbility 的完整生命周期和窗口管理机制。核心要点如下:
- UIAbility 是 Stage 模型的核心入口,管理着应用的生命周期和窗口
- onCreate → onWindowStageCreate → onForeground 是启动时的标准流程
- onWindowStageCreate 是最重要的回调,负责加载首屏和配置窗口
- hilog 日志系统为应用调试提供了有力支持
- module.json5 中的配置直接影响 Ability 的行为
下一篇文章将深入讲解 WindowStage 窗口管理,包括透明状态栏的实现、沉浸式布局的适配以及安全区域的处理,敬请期待。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源: