HarmonyOs应用《日记本》开发第2篇 - Stage模型
HarmonyOS 提供了两种应用模型:FA(Feature Ability)模型和 Stage 模型。从 HarmonyOS 3.1开始,Stage 模型成为官方推荐的应用开发模型。我们的日记应用正是基于 Stage 模型构建的。本篇将深入解析 Stage模型的核心概念,并通过日记项目的实际代码来理解其工作原理。
Stage 模型 vs FA 模型
核心区别
| 特性 | FA 模型 | Stage 模型 |
|---|---|---|
| 开发范式 | 类 Ace 开发 | ArkTS 声明式 |
| 组件模型 | PageAbility / ServiceAbility | UIAbility / ExtensionAbility |
| 配置文件 | config.json | module.json5 |
| 生命周期 | 较简单 | 更完善,支持多实例、多窗口 |
| UI 开发 | JS/ArkTS 混合 | 纯 ArkTS 声明式 |
| 数据共享 | DataAbility | DataShareExtensionAbility |
为什么选择 Stage 模型
- 更清晰的架构:UI 与业务逻辑分离,UIAbility 专注窗口管理
- 更强大的生命周期:支持前后台切换、多窗口、多实例
- 更好的扩展性:ExtensionAbility 支持多种场景扩展
- 统一的配置体系:json5 格式配置,更灵活可读
Stage 模型的核心概念
1. UIAbility
UIAbility 是 Stage 模型中带有 UI 界面的组件,负责与用户交互。在我们的日记应用中:
// EntryAbility.etsimport{UIAbility,AbilityConstant,Want}from'@kit.AbilityKit';import{window}from'@kit.ArkUI';import{diaryStore}from'../utils/DiaryStore';exportdefaultclassEntryAbilityextendsUIAbility{asynconCreate(want:Want,launchParam:AbilityConstant.LaunchParam):Promise<void>{// 初始化数据存储awaitdiaryStore.init(this.context);}onWindowStageCreate(windowStage:window.WindowStage):void{windowStage.loadContent('pages/Index',(err)=>{if(err.code){console.error('Failed to load content. cause: '+JSON.stringify(err));return;}console.info('Succeeded in loading content.');});}}2. WindowStage
WindowStage 是窗口管理器,每个 UIAbility 实例都持有一个 WindowStage,负责加载和管理 UI 内容:
onWindowStageCreate(windowStage:window.WindowStage):void{// 加载入口页面windowStage.loadContent('pages/Index',(err)=>{// 回调处理});}3. Context
Context 是应用上下文对象,提供了访问应用资源、文件系统、偏好存储等能力。在日记项目中,Context 被传递给 DiaryStore 进行数据初始化:
asynconCreate(want:Want,launchParam:AbilityConstant.LaunchParam):Promise<void>{awaitdiaryStore.init(this.context);// this.context 即 UIAbility 的上下文}DiaryStore 接收 Context 并初始化 Preferences:
asyncinit(context:Context):Promise<void>{this.store=awaitpreferences.getPreferences(context,{name:'diary_store'});}UIAbility 生命周期详解
Stage 模型中 UIAbility 的生命周期比 FA 模型更加丰富:
应用启动 │ ▼ onCreate(want, launchParam) │ → 初始化数据存储 ▼ onWindowStageCreate(windowStage) │ → 加载首页 pages/Index ▼ onForeground() │ → 应用进入前台,可交互 ▼ [用户使用中...] │ ▼ onBackground() │ → 应用进入后台 ▼ onWindowStageDestroy() │ → 窗口销毁 ▼ onDestroy() │ → Ability 销毁 ▼ [进程可能被回收]日记项目中的生命周期实现
exportdefaultclassEntryAbilityextendsUIAbility{// 1. Ability 创建时调用asynconCreate(want:Want,launchParam:AbilityConstant.LaunchParam):Promise<void>{awaitdiaryStore.init(this.context);}// 2. 新的调用(singleInstance 模式下会触发)onNewSession(want:Want,launchParam:AbilityConstant.LaunchParam):void{}// 3. 窗口创建时调用onWindowStageCreate(windowStage:window.WindowStage):void{windowStage.loadContent('pages/Index',(err)=>{if(err.code){console.error('Failed to load content. cause: '+JSON.stringify(err));return;}console.info('Succeeded in loading content.');});}// 4. 窗口销毁时调用onWindowStageDestroy():void{}// 5. 应用进入前台onForeground():void{}// 6. 应用进入后台onBackground():void{}// 7. Ability 销毁onDestroy():void{}}生命周期中的数据初始化策略
在本项目中,数据存储的初始化放在onCreate中:
asynconCreate(want:Want,launchParam:AbilityConstant.LaunchParam):Promise<void>{awaitdiaryStore.init(this.context);}为什么放在 onCreate?
onCreate是 Ability 生命周期的第一个回调- 此时 Context 已经可用,可以安全地初始化存储
- 在
onWindowStageCreate加载 UI 之前完成,确保页面加载数据时存储已就绪 - 使用
await确保异步初始化完成后再继续
Want 机制
onCreate接收的want参数包含了启动 Ability 时传递的信息:
interfaceWant{bundleName?:string;// 目标包名abilityName?:string;// 目标 Ability 名uri?:string;// URItype?:string;// MIME 类型parameters?:Record<string,Object>;// 自定义参数}在日记应用中,want由系统在桌面图标点击时传入,携带了entity.system.home和action.system.home信息,使应用作为桌面入口启动。
module.json5 中的 Ability 配置
Stage 模型的配置在module.json5中完成:
{ "module": { "name": "entry", "type": "entry", "description": "$string:module_desc", "mainElement": "EntryAbility", "deviceTypes": ["phone", "tablet"], "deliveryWithInstall": true, "installationFree": false, "pages": "$profile:main_pages", "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"] } ] } ] } }关键字段解读:
| 字段 | 说明 |
|---|---|
mainElement | 模块的主入口 Ability |
srcEntry | Ability 源码路径 |
deviceTypes | 支持的设备类型 |
pages | 页面路由配置,指向$profile:main_pages |
skills | 声明 Ability 可响应的意图 |
exported | 是否允许其他应用调用 |
startWindowIcon | 启动窗口图标 |
startWindowBackground | 启动窗口背景色 |
Stage 模型的页面加载机制
在 Stage 模型中,页面路由通过main_pages.json配置:
{"src":["pages/Index","pages/DiaryEdit","pages/DiaryDetail"]}页面之间通过router模块进行导航:
import{router}from'@kit.ArkUI';// 跳转到编辑页router.pushUrl({url:'pages/DiaryEdit'});// 跳转到详情页并传参router.pushUrl({url:'pages/DiaryDetail',params:{id:item.id}});// 返回上一页router.back();小结
Stage 模型是 HarmonyOS 推荐的应用开发模型,提供了更清晰的架构设计和更强大的生命周期管理。通过日记项目的EntryAbility实现,我们理解了:
- UIAbility 是 UI 交互的核心载体
- 生命周期回调各有分工,
onCreate负责初始化,onWindowStageCreate负责加载 UI - Context 是访问系统能力的桥梁
- module.json5 是 Stage 模型的核心配置文件