HarmonyOS应用开发实战:猫猫大作战-在 HarmonyOS 应用中,WindowStage(窗口舞台)是连接 UIAbility 与页面的中间枢纽
前言在 HarmonyOS 应用中WindowStage窗口舞台是连接 UIAbility 与页面的中间枢纽——它负责管理应用窗口的创建、显示、隐藏、销毁全周期并承载loadContent加载首屏页面。理解onWindowStageCreate回调的完整能力是写出流畅、健壮的 ArkUI 应用的基础。本文以「猫猫大作战」的EntryAbility为锚点深入onWindowStageCreate中的窗口事件订阅、窗口属性配置、多窗口适配以及 WindowStageEventType 六种状态变化。提示本系列不讲 ArkTS 基础语法与环境搭建假设你已跟完第 1–73 篇。本篇是阶段三第 74 篇。一、WindowStage 是什么1.1 角色定位UIAbility应用组件 │ │ 拥有 ▼ WindowStage窗口舞台 │ │ 包含 ▼ Window窗口—— 承载 UI 内容 │ │ 加载 ▼ ArkUI 页面Index.ets层级职责生命周期回调UIAbility应用组件的生命周期管理onCreate → onForeground → onBackground → onDestroyWindowStage窗口舞台的管理onWindowStageCreate → onWindowStageWillDestroy → onWindowStageDestroyWindow窗口属性与事件SHOWN / ACTIVE / INACTIVE / HIDDEN / RESUMED / PAUSED1.2 猫猫大作战中的 WindowStageimport { UIAbility, Want, AbilityConstant } from kit.AbilityKit; import { window } from kit.ArkUI; import { hilog } from kit.PerformanceAnalysisKit; export default class EntryAbility extends UIAbility { private windowStageObj: window.WindowStage | undefined undefined; onWindowStageCreate(windowStage: window.WindowStage): void { hilog.info(0xFF00, EntryAbility, onWindowStageCreate); this.windowStageObj windowStage; // 订阅窗口事件 windowStage.on(windowStageEvent, (data) { this.handleWindowStageEvent(data); }); // 加载首屏 windowStage.loadContent(pages/Index, (err) { if (err.code) { hilog.error(0xFF00, EntryAbility, 加载失败: %{public}s, JSON.stringify(err)); return; } hilog.info(0xFF00, EntryAbility, 首屏加载成功); }); } onWindowStageWillDestroy(windowStage: window.WindowStage): void { // 销毁前注销订阅 windowStage.off(windowStageEvent); this.windowStageObj undefined; } onWindowStageDestroy(): void { hilog.info(0xFF00, EntryAbility, onWindowStageDestroy); } }二、WindowStageEventType 六种状态2.1 状态枚举事件类型含义触发时机项目用途SHOWN窗口切到前台应用从后台回到前台恢复游戏引擎ACTIVE窗口获焦用户与窗口交互启动游戏定时器INACTIVE窗口失焦用户拉下通知栏暂停游戏HIDDEN窗口切到后台用户按 Home 键暂停游戏、释放资源RESUMED前台可交互窗口完全就绪继续游戏PAUSED前台不可交互窗口被部分遮挡降帧省电2.2 完整状态机┌─────────┐ │ SHOWN │ ← 窗口进入前台 └────┬────┘ │ ┌────▼────┐ ┌───│ ACTIVE │ ← 获焦 │ └────┬────┘ │ │ │ ┌────▼────┐ │ │ RESUMED │ ← 可交互 │ └────┬────┘ │ │ INACTIVE ◄────┘ ← 失焦如通知栏下拉 │ │ ┌─────────┐ └──►│ PAUSED │ ← 前台不可交互 └────┬────┘ │ ┌────▼────┐ │ HIDDEN │ ← 完全进入后台 └─────────┘2.3 实战根据窗口事件控制游戏private handleWindowStageEvent(eventType: window.WindowStageEventType): void { switch (eventType) { case window.WindowStageEventType.SHOWN: hilog.info(0xFF00, EntryAbility, 窗口回到前台); // 通知游戏页面恢复 AppStorage.setOrCreate(windowState, foreground); break; case window.WindowStageEventType.ACTIVE: hilog.info(0xFF00, EntryAbility, 窗口获焦); break; case window.WindowStageEventType.INACTIVE: hilog.info(0xFF00, EntryAbility, 窗口失焦 — 暂停游戏); // 失焦时暂停防止操作继续 AppStorage.setOrCreate(windowState, inactive); AppStorage.setOrCreate(gamePausedBySystem, true); break; case window.WindowStageEventType.HIDDEN: hilog.info(0xFF00, EntryAbility, 窗口进入后台 — 释放资源); AppStorage.setOrCreate(windowState, background); break; case window.WindowStageEventType.RESUMED: hilog.info(0xFF00, EntryAbility, 前台可交互 — 继续游戏); break; case window.WindowStageEventType.PAUSED: hilog.info(0xFF00, EntryAbility, 前台不可交互 — 暂停动画); break; default: break; } }三、窗口属性配置3.1 获取 Window 对象通过windowStage.getMainWindow()获取Window对象配置窗口属性async onWindowStageCreate(windowStage: window.WindowStage): Promisevoid { try { const windowClass await windowStage.getMainWindow(); // 设置窗口全屏 windowClass.setWindowLayoutFullScreen(true); // 设置窗口背景色 windowClass.setWindowBackgroundColor(#E8F4F8); // 禁止窗口大小调整 windowClass.setWindowResizable(false); // 设置窗口是否保持常亮 windowClass.setWindowKeepScreenOn(true); hilog.info(0xFF00, EntryAbility, 窗口属性配置完成); } catch (err) { hilog.error(0xFF00, EntryAbility, 窗口配置失败: %{public}s, JSON.stringify(err)); } windowStage.loadContent(pages/Index); }3.2 常用窗口属性属性方法游戏场景用途全屏模式setWindowLayoutFullScreen(true)沉浸式游戏体验保持常亮setWindowKeepScreenOn(true)游戏过程中不锁屏背景色setWindowBackgroundColor(#E8F4F8)与应用主色调匹配允许调整setWindowResizable(false)固定棋盘布局横竖屏setWindowPreferredOrientation()锁定竖屏游戏3.3 窗口属性最佳实践async onWindowStageCreate(windowStage: window.WindowStage): Promisevoid { const windowClass await windowStage.getMainWindow(); // 锁定为竖屏 try { windowClass.setWindowPreferredOrientation( window.Orientation.PORTRAIT ); } catch { // 部分设备不支持锁定方向 } // 保持屏幕常亮 windowClass.setWindowKeepScreenOn(true); windowStage.loadContent(pages/Index); }四、onWindowStageWillDestroy 与资源释放4.1 与 onWindowStageDestroy 的区别应用退出流程 onWindowStageWillDestroy(windowStage) ├── WindowStage 仍然可用 ├── 在此注销窗口事件、释放窗口资源 └── 执行完毕后 WindowStage 被销毁 onWindowStageDestroy() └── WindowStage 已被销毁无法操作 └── 仅作为日志通知回调回调WindowStage 可用用途onWindowStageWillDestroy✅ 可用注销事件、释放资源onWindowStageDestroy❌ 不可用仅日志记录4.2 正确释放资源export default class EntryAbility extends UIAbility { private windowStageObj: window.WindowStage | undefined undefined; onWindowStageCreate(windowStage: window.WindowStage): void { this.windowStageObj windowStage; // 订阅窗口事件 windowStage.on(windowStageEvent, this.handleWindowStageEvent.bind(this)); windowStage.loadContent(pages/Index); } onWindowStageWillDestroy(windowStage: window.WindowStage): void { // ✅ 正确的释放位置WindowStage 还未销毁 try { windowStage.off(windowStageEvent); // 注销事件 this.windowStageObj undefined; // 释放引用 hilog.info(0xFF00, EntryAbility, 窗口资源已释放); } catch (err) { hilog.error(0xFF00, EntryAbility, 释放失败); } } onWindowStageDestroy(): void { // ❌ 此时 WindowStage 已销毁只能记录日志 hilog.info(0xFF00, EntryAbility, WindowStage 已销毁); } }五、多窗口与分屏适配5.1 窗口大小变化监听async onWindowStageCreate(windowStage: window.WindowStage): Promisevoid { const windowClass await windowStage.getMainWindow(); // 监听窗口大小变化 windowClass.on(windowSizeChange, (size: window.Size) { hilog.info(0xFF00, EntryAbility, 窗口大小变化: ${size.width}x${size.height}); // 根据窗口宽度判断布局模式 if (size.width 600) { AppStorage.setOrCreate(layoutMode, compact); } else if (size.width 840) { AppStorage.setOrCreate(layoutMode, medium); } else { AppStorage.setOrCreate(layoutMode, expanded); } }); windowStage.loadContent(pages/Index); }5.2 分屏/悬浮窗场景// 在分屏模式下窗口面积缩小可以做相应调整 windowClass.on(windowSizeChange, (size: window.Size) { if (size.width 400 || size.height 400) { // 极小窗口隐藏非核心 UI简化棋盘渲染 AppStorage.setOrCreate(simplifiedMode, true); } else { AppStorage.setOrCreate(simplifiedMode, false); } });六、WindowStage 与 UIAbility 的关联6.1 完整生命周期对照时序UIAbility 回调WindowStage 回调窗口状态①onCreate——②—onWindowStageCreateWindowStage 创建③——loadContent 加载页面④onForeground—窗口可见⑤—SHOWN / ACTIVE窗口获焦可交互⑥onBackgroundHIDDEN窗口进入后台⑦—onWindowStageWillDestroyWindowStage 即将销毁⑧—onWindowStageDestroyWindowStage 已销毁⑨onDestroy—UIAbility 销毁6.2 关键设计原则原则 1WindowStage 的事在 WindowStage 回调中完成 原则 2loadContent 必须在 onWindowStageCreate 中调用 原则 3窗口事件订阅必须在 onWindowStageWillDestroy 中注销 原则 4首屏路径必须与 main_pages.json 注册一致七、常见踩坑7.1 坑一在 onWindowStageDestroy 中操作窗口// 错误onWindowStageDestroy 中 WindowStage 已不可用 onWindowStageDestroy(): void { this.windowStageObj?.loadContent(pages/Other); // ❌ 会崩溃 } // ✅ 正确在 onWindowStageWillDestroy 中释放 onWindowStageWillDestroy(windowStage: window.WindowStage): void { windowStage.off(windowStageEvent); }7.2 坑二忘记注销窗口事件订阅onWindowStageCreate(windowStage) { windowStage.on(windowStageEvent, callback); // 注册了 // 但 onWindowStageWillDestroy 中忘记注销 → 内存泄漏 }八、总结onWindowStageCreate是 WindowStage 生命周期的起点它连接了 UIAbility 与 UI 页面。通过窗口事件订阅可以精确感知获焦/失焦、前台/后台切换配合窗口属性配置可以实现全屏、常亮、锁定横竖屏等游戏场景关键能力。核心要点onWindowStageCreate中订阅窗口事件、配置窗口属性、加载首屏页面六种窗口事件类型SHOWN/ACTIVE/INACTIVE/HIDDEN/RESUMED/PAUSEDonWindowStageWillDestroy中注销事件、释放资源windowStage.getMainWindow()获取 Window 对象配置窗口属性监听windowSizeChange适配分屏/多窗口下一篇预告第 75 篇将深入onForeground/onBackground— 前后台切换时如何暂停和恢复游戏。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源UIAbility 生命周期文档WindowStage API 参考窗口生命周期文档WindowStageEventType 枚举应用冷启动优化开源鸿蒙跨平台社区第 73 篇loadContent 首屏绑定第 75 篇onForeground/onBackground

相关新闻

Applera1n:iOS 15-16.6激活锁绕过终极解决方案深度解析

Applera1n:iOS 15-16.6激活锁绕过终极解决方案深度解析

Applera1n:iOS 15-16.6激活锁绕过终极解决方案深度解析 【免费下载链接】applera1n icloud bypass for ios 15-16 项目地址: https://gitcode.com/gh_mirrors/ap/applera1n 在iOS设备安全领域,激活锁(Activation Lock)一直…

2026/10/20 1:12:52 阅读更多 →
HarmonyOS应用开发实战:猫猫大作战-Tabs 的声明式用法、自定义 TabBar 样式、事件监听和性能优化

HarmonyOS应用开发实战:猫猫大作战-Tabs 的声明式用法、自定义 TabBar 样式、事件监听和性能优化

前言 在多页面应用中,底部导航栏是最常见的导航模式之一——微信、淘宝等主流应用都采用 Tab 切换不同功能模块。HarmonyOS 的 Tabs 组件提供了原生的底部/顶部导航能力,配合 TabContent 容器实现标签页切换。 本文以「猫猫大作战」中“主页/排行榜/我…

2026/10/20 12:33:15 阅读更多 →
HarmonyOS应用开发实战:猫猫大作战-NavDestination 的结构组成、自定义标题栏、菜单栏和工具栏以及生命周期管理

HarmonyOS应用开发实战:猫猫大作战-NavDestination 的结构组成、自定义标题栏、菜单栏和工具栏以及生命周期管理

前言 NavDestination 是 Navigation 路由体系中每个“页面“的容器——它提供标题栏、工具栏、菜单栏、返回按钮等页面级 UI 结构,同时管理页面内容的渲染。每个通过 pushPath 进入的“页面“实际上都是一个 NavDestination 实例。 本文以「猫猫大作战」中排行榜详…

2026/10/18 14:51:17 阅读更多 →

最新新闻

Frida动态插桩实战:从Hook到内存扫描的完整指南

Frida动态插桩实战:从Hook到内存扫描的完整指南

做移动端安全测试这些年,我见过太多人把大量时间花在反编译和读汇编上,遇到加了壳的应用就只能干瞪眼。后来我开始把 Frida 动态插桩作为主要分析手段,很多原本要折腾半天的任务,现在几分钟就能拿到结果。这篇文章我会从最基础的 …

2026/10/20 14:48:08 阅读更多 →
C++实战:用VS编写贪吃蛇游戏的核心逻辑与完整源码

C++实战:用VS编写贪吃蛇游戏的核心逻辑与完整源码

用VS和C写一个贪吃蛇游戏,听起来很基础,但真做起来,里面藏着不少值得抠的细节。我把完整源码放在下面,你在Visual Studio里新建一个控制台应用,复制进去就能编译运行。对刚学完C语法、想做点东西验证自己的入门者来说&…

2026/10/20 14:48:08 阅读更多 →
工业时序建模:分清机理与机制,才能让模型长出筋骨

工业时序建模:分清机理与机制,才能让模型长出筋骨

1. 先把"机理"这层窗户纸捅破:确定性因果链做工业数据建模这些年,最常碰见的尴尬不是算法调不好,而是开会时一屋子人对着"机理"和"机制"这两个词各说各话。做设备的老师傅嘴里的"机理清楚"&#xff…

2026/10/20 14:48:08 阅读更多 →
机房管理系统落地指南:从SNMP/IPMI选型到告警联动与避坑实践

机房管理系统落地指南:从SNMP/IPMI选型到告警联动与避坑实践

简介:一套面向高校数据库课程设计的机房管理系统完整资料,覆盖机房信息、设备信息、用户信息、预约信息和使用记录等核心业务实体,并针对资源调度、冲突避免与使用分析给出明确的数据组织方案。资源共三个文件,包含两份文档和一份…

2026/10/20 14:48:08 阅读更多 →
融合敏感度先验的条件扩散模型:电阻抗成像重建新思路

融合敏感度先验的条件扩散模型:电阻抗成像重建新思路

最近整理手头的一个电阻抗成像项目代码和实验记录,想把这套技术路线从头到尾理清楚。电阻抗成像(Electrical Impedance Tomography,EIT)本质上就是个逆问题:边界贴电极,注入已知电流,测一组电压…

2026/10/20 14:48:08 阅读更多 →
60次实测:MCP不省上下文,子agent平均省38.1%token增量

60次实测:MCP不省上下文,子agent平均省38.1%token增量

做Agent应用的人,大概都被问过一个问题:接上MCP之后,上下文是不是就能省不少?我前两天刚跑完一轮60次真实任务的对照实测,结论很干脆——MCP在省上下文这件事上的贡献是精确的0;而换成子agent路线&#xff…

2026/10/20 14:46:40 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →