引言
随着HarmonyOS 4.0的全面推广,Stage模型已经成为华为鸿蒙应用开发的标准架构。相比于传统的FA模型(Feature Ability),Stage模型在设计理念、组件管理、生命周期以及多设备协同等方面都有了质的飞跃。然而,许多开发者在初次接触时,都会被AbilityStage、UIAbility、WindowStage、页面路由这些新概念绕晕。本文将带你从核心概念出发,通过一个完整的可运行示例,彻底吃透Stage模型,让鸿蒙开发不再神秘。
一、核心概念:Stage模型是什么?
Stage模型是HarmonyOS应用开发的一种全新架构,它将应用划分为两个核心层级:应用级和窗口级。
- 应用级(AbilityStage):代表整个应用,管理所有组件的全局状态,在应用初始化时最先被创建。你可以在这里做一些全局的初始化操作,比如埋点、预加载数据等。
- 窗口级(UIAbility & WindowStage):UIAbility是具备用户界面的能力单元,一个应用可以有多个UIAbility,每个UIAbility通过WindowStage来管理自己的窗口界面。WindowStage负责窗口的创建、显示、隐藏以及页面之间的导航。
简单理解:AbilityStage是老板,UIAbility是部门,WindowStage是部门的办公室,而页面(Pages)就是办公室里正在处理的文件。
Stage模型还引入了组件生命周期和页面生命周期的解耦,使得应用能够更精确地控制资源,支持灵活的多窗口和多设备流转。
二、关键生命周期解析
在Stage模型中,有两个重要的生命周期需要掌握:
1. AbilityStage生命周期
AbilityStage在应用启动时创建,主要提供onCreate()回调:
import AbilityStage from '@ohos.app.ability.AbilityStage'; export default class MyAbilityStage extends AbilityStage { onCreate(): void { // 应用启动时触发,可做全局初始化,比如日志、网络配置等 console.info('MyAbilityStage onCreate'); } }2. UIAbility生命周期
UIAbility负责与用户交互,包含四种主要状态:
- Create:UIAbility实例创建,
onCreate(want, launchParam)被调用。 - Foreground:UIAbility切换到前台,
onForeground()触发,此时用户可以交互。 - Background:UIAbility切换到后台(如用户返回桌面),
onBackground()触发,需保存关键状态。 - Destroy:UIAbility被销毁,
onDestroy()执行,释放资源。
每个UIAbility还会关联一个WindowStage,通过onWindowStageCreate(windowStage)来加载页面。
三、实战示例:一个拥有两个页面的Stage应用
下面我们通过一个完整的HarmonyOS项目,演示如何在Stage模型中创建一个UIAbility,并实现页面间的跳转。
3.1 项目结构
entry/src/main/ets/ ├── entryability/ │ └── EntryAbility.ts ├── pages/ │ ├── Index.ets │ └── Second.ets └── app.ets (AbilityStage实现)3.2 编写AbilityStage
在app.ets中定义全局的AbilityStage:
// app.ets import AbilityStage from '@ohos.app.ability.AbilityStage'; export default class MyAbilityStage extends AbilityStage { onCreate(): void { console.info('[MyAbilityStage] onCreate, 应用全局初始化'); // 可以在这里初始化网络管理器、SDK等 } }3.3 编写UIAbility(EntryAbility.ts)
// EntryAbility.ts import UIAbility from '@ohos.app.ability.UIAbility'; import window from '@ohos.window'; import Want from '@ohos.app.ability.Want'; export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: object): void { console.info('[EntryAbility] onCreate'); } onDestroy(): void { console.info('[EntryAbility] onDestroy'); } onWindowStageCreate(windowStage: window.WindowStage): void { console.info('[EntryAbility] onWindowStageCreate'); // 加载主页面 windowStage.loadContent('pages/Index', (err) => { if (err.code) { console.error('Failed to load the content. Cause: ' + JSON.stringify(err)); return; } console.info('Succeeded in loading the content.'); }); } onWindowStageDestroy(): void { console.info('[EntryAbility] onWindowStageDestroy'); } onForeground(): void { console.info('[EntryAbility] onForeground'); } onBackground(): void { console.info('[EntryAbility] onBackground'); } }3.4 编写主页 Index.ets
主页包含一个按钮,点击后跳转到第二页。
// Index.ets import router from '@ohos.router'; @Entry @Component struct Index { @State message: string = 'Hello Stage Model'; build() { Row() { Column() { Text(this.message) .fontSize(30) .fontWeight(FontWeight.Bold) .margin({ bottom: 20 }) Button('跳转到第二页') .fontSize(20) .onClick(() => { // 使用router.pushUrl实现页面跳转 router.pushUrl({ url: 'pages/Second', params: { source: '来自首页的数据' } }).then(() => { console.info('跳转成功'); }).catch((err: Error) => { console.error('跳转失败: ' + JSON.stringify(err)); }) }) } .width('100%') } .height('100%') } }3.5 编写第二页 Second.ets
第二页显示从首页传递过来的参数,并提供返回按钮。
// Second.ets import router from '@ohos.router'; @Entry @Component struct Second { @State receivedParams: string = ''; aboutToAppear(): void { // 获取路由传递的参数 const params = router.getParams() as Record<string, Object>; if (params && params['source']) { this.receivedParams = params['source'] as string; } } build() { Row() { Column() { Text('第二页') .fontSize(30) .fontWeight(FontWeight.Bold) .margin({ bottom: 20 }) Text(`接收到的参数: ${this.receivedParams}`) .fontSize(18) .margin({ bottom: 30 }) Button('返回首页') .fontSize(20) .onClick(() => { router.back(); // 返回上一页 }) } .width('100%') } .height('100%') } }3.6 配置文件 module.json5
确保module.json5中正确配置了Ability和页面路由:
{ "module": { "name": "entry", "type": "entry", "srcEntry": "./ets/entryability/EntryAbility.ts", "abilities": [ { "name": "EntryAbility", "srcEntry": "./ets/entryability/EntryAbility.ts", "launchType": "singleton", "visible": true, "skills": [ { "entities": ["entity.system.home"], "actions": ["action.system.home"] } ] } ] } }注意:页面路由
pages/Index和pages/Second需要已经在resources/base/profile/main_pages.json中注册。
四、常见问题与注意事项
页面必须在main_pages.json中注册
Stage模型的路由依赖于显式声明的页面列表。如果页面未注册,router.pushUrl会失败。main_pages.json内容示例:json { "src": [ "pages/Index", "pages/Second" ] }Ability的launchType
-singleton:单例,全局唯一,已推荐大部分场景使用。
-multiton:多实例,每次启动创建新实例。
-standard:标准模式,不同场景可创建不同实例。资源释放
在onBackground()中应保存关键状态,在onDestroy()中务必释放图片缓存、监听器等资源,避免内存泄漏。路由传参的大小限制
通过router传递的参数序列化后不得超过100KB,大数据量建议通过全局数据管理或文件方式共享。AbilityStage非必需
如果你的应用无需全局初始化,可以省略app.ets文件,系统会使用默认的AbilityStage实现。
五、总结
Stage模型是HarmonyOS应用开发的基石,理解AbilityStage、UIAbility和WindowStage的协作关系,是编写高质感鸿蒙应用的第一步。本文通过完整的代码示例,展示了从创建Ability到页面跳转的全过程,希望能帮助你快速上手。
在实际项目中,你还会接触到ServiceAbility(无UI的后台能力)、DataAbility(数据共享)以及最新的元服务等扩展。但万变不离其宗,抓住Stage模型的主线——应用-窗口两级管理,职责清晰,生命周期可控,就能从容应对各种场景。
如果你在实践过程中遇到其他问题,欢迎在评论区交流,一起探索HarmonyOS的无限可能。