本节摘要:Stage 模型是 API 9 起的 HarmonyOS 应用模型。本节解剖工程目录与核心组件(UIAbility、AbilityStage、ExtensionAbility),讲清从 FA 到 Stage 换代的设计动机,并通过给工程加一行日志验证页面加载链路。
一个新建的 Stage 工程乍看文件不少,但主干只有三处。把这三处看懂,其他都是围绕它们的资源与配置:
| 位置 | 角色 | 你什么时候会改它 |
|---|---|---|
| AppScope/app.json5 | 应用级身份:包名、版本号、图标名称 | 改版本、改应用名 |
| entry/src/main/module.json5 | 模块级能力:入口 Ability、权限、设备类型 | 加权限、加页面入口、上分布式 |
| entry/src/main/ets/entryability/EntryAbility.ets | 第一个 UIAbility 的实现 | 应用启动逻辑、窗口与生命周期 |
UIAbility 是 Stage 模型里承载界面的基本单元。一个应用可以有多个 UIAbility(比如相册的浏览与编辑各一个),也可以只有一个。应用启动时系统创建 UIAbility,它经历自己的生命周期,在窗口就绪的回调里加载你的第一个页面——这就是 Hello World 能出现的完整原因。
打开 EntryAbility.ets,找到 onWindowStageCreate 回调,里面有类似一行:
windowStage.loadContent('pages/Index', (err) => { if (err.code) { hilog.error(0x0000, 'EntryAbility', 'Failed to load content.'); return; } hilog.info(0x0000, 'EntryAbility', 'Succeeded in loading content.'); });
loadContent 接收的 'pages/Index' 就是页面路径。现在动手验证这条链路:新建一个页面文件 Second(在 pages 目录上右键、New、Page,带装饰器骨架),然后把 loadContent 的参数改成 'pages/Second',重新运行——应用首页变成了新页面。改一个字符串就换了入口页面,这说明"显示哪个页面"只是 UIAbility 加载逻辑的一行配置,不是什么神秘机制。改回 Index,继续。

旧 FA 模型把 Ability 分成两类:Feature Ability 管界面、Particle Ability 管服务与数据,再加一整套 Page/Service/Data 的Ability切片概念,边界多、心智负担重。Stage 模型的思路是收敛:界面统一交给 UIAbility;不需要界面的扩展能力(卡片、输入法、后台任务)各归各的 ExtensionAbility 类型;模块加载有了统一的 AbilityStage 入口做初始化。
对开发者最实际的三个变化:其一,页面不再需要在配置里逐个注册路由(FA 时代的页面要写进配置,漏了就白屏),Stage 的页面就是 ArkTS 文件,路径加载即可——前面 loadContent 实验已验证;其二,生命周期更清晰,前台后台与窗口分离,写多端流转(第 7 章)时会再次受益;其三,ExtensionAbility 让"卡片这类无界面形态"成为一等公民,第 7 章写元服务卡片时就是从它派生。
💡 关键直觉:把 UIAbility 理解为"一个带窗口的任务",把页面理解为"窗口里可替换的内容"。一个 UIAbility 可以在生命周期内多次 loadContent 换页面,也可以多个 UIAbility 各自开窗口。这个心智模型在后面做流转时特别有用——流转的本质之一就是把 UIAbility 的状态搬到另一台设备。
生命周期不能只背名字,打日志看一遍最直接。在 EntryAbility.ets 的 onCreate、onForeground、onBackground 里各加一行:
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; const DOMAIN = 0x0001; const TAG = 'LifeCycle'; export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { hilog.info(DOMAIN, TAG, 'onCreate:应用进程创建,适合做全局初始化'); } onForeground(): void { hilog.info(DOMAIN, TAG, 'onForeground:回到前台,恢复动画与刷新'); } onBackground(): void { hilog.info(DOMAIN, TAG, 'onBackground:退到后台,适合保存状态、停掉计时器'); } }
运行应用,然后操作:按 Home 键回桌面、再从任务列表切回来、最后从任务列表划掉应用。打开 IDE 底部 Log 窗口,用 TAG 过滤,你会看到 onCreate 只出现一次,onForeground/onBackground 成对出现,且符合操作顺序。
解读这套实验:onCreate 对应进程级的一次性初始化;前后台切换频繁,所以刷新类逻辑放 onForeground、资源释放放 onBackground;而页面级的生命周期是另一条线(第 3 章讲页面组件的 aboutToAppear 时会接上)。分清"进程级、Ability 级、组件级"三层生命周期,是后面一切状态保存与恢复的基础。
⚠️ 常见坑:在 onCreate 里拿 windowStage 做事——那时窗口还没创建好。窗口相关的操作要等 onWindowStageCreate 回调,也就是 loadContent 所在的位置。
骨架已经清楚,但 Index 页面里那串 @Entry、@Component、build 还没拆。下一节我们从零手写一个登录页,把页面语法的三层结构一次讲透。