3-7.【Ability】页面生命周期与 UIAbility 生命周期如何配合?页面销毁是否一定意味着 Ability 销毁?

2 阅读3分钟

页面生命周期与 UIAbility 生命周期如何配合?页面销毁是否一定意味着 Ability 销毁?一个 Ability 内多个页面如何管理资源?

在 ArkTS 的架构中,UIAbility 是“容器”,而 页面(Page) 是“内容”。理解它们的嵌套关系和生命周期步调,是解决应用闪退、掉帧和内存增长的关键。


1. 页面与 UIAbility 生命周期的配合

它们的关系类似于“大盒子”与“小盒子”。当大盒子移动时,里面的小盒子必然随之移动。

典型的配合流程(以冷启动为例):

  1. Ability 启动: 执行 onCreate
  2. 加载内容: onWindowStageCreate 调用 windowStage.loadContent('pages/Index')
  3. 页面初始化: 页面组件触发 aboutToAppear
  4. Ability 变为可见: 执行 onForeground
  5. 页面变为可见: 页面触发 onPageShow

生命周期对照表:

动作UIAbility 生命周期页面 (Page) 生命周期
应用进入后台onBackgroundonPageHide
从后台切回前台onForegroundonPageShow
用户点击返回键退出页面(不触发,除非是最后一个页面)onBackPress \rightarrow aboutToDisappear
系统销毁 Ability 实例onDestroyaboutToDisappear

2. 页面销毁是否一定意味着 Ability 销毁?

结论:不一定。

这取决于当前的**路由栈(Router Stack)**状态:

  • 场景 A(非销毁): 当你从 PageA 跳转到 PageB(使用 router.pushUrl)时,PageA 仅触发 onPageHide,它并没有销毁,而是被压入栈底。此时 UIAbility 稳如泰山。
  • 场景 B(页面销毁但 Ability 存活): 当你从 PageB 返回 PageA(调用 router.back)时,PageB 会触发 aboutToDisappear 并被销毁,但 UIAbility 依然存活,因为它还在展示 PageA
  • 场景 C(共同销毁): 当你在栈底页面(主页)点击返回键时,页面执行销毁,由于没有更多页面可显示,UIAbility 也会随之进入 onWindowStageDestroyonDestroy

3. 一个 Ability 内多个页面的资源管理

在单 Ability 多页面(Single Ability Multi-Page)架构下,资源管理需要极度精细,否则随着跳转次数增加,内存会迅速“爆表”。

A. 巧用 LocalStorage 进行物理隔离

不要把所有页面的状态都塞进全局的 AppStorage

  • 实践: 在 Ability 加载时创建一个 LocalStorage 实例。
  • 好处: 页面可以通过 @LocalStorageLink 共享数据,而当 UIAbility 销毁时,这个 LocalStorage 会被整体回收,干净利落。

B. 区分“可见性释放”与“彻底销毁释放”

  • onPageHide 阶段: 适合释放高频刷新的资源。例如:停止页面上的计时器、暂停视频播放、取消高频传感器订阅。
  • aboutToDisappear 阶段: 适合释放内存占用大的资源。例如:置空大的图片数组、解绑全局事件监听(Emitter)、销毁自定义的后台 Worker。

C. 路由缓存机制与页面限制

  • 栈深度限制: 页面栈最大深度为 32。达到上限后无法 push。
  • 清栈操作: 对于登录页、引导页等“一去不复返”的页面,跳转时应使用 router.replaceUrl 而不是 pushUrl。这样旧页面会立即触发 aboutToDisappear 释放资源,而不是留在栈底吃内存。

总结

  1. Ability 是环境,Page 是状态:环境不可见时(onBackground),所有 Page 都会隐藏(onPageHide)。
  2. 生命周期成对原则:在 aboutToAppear 申请的非 UI 资源(如长连接),必须在 aboutToDisappear 手动断开。
  3. 按需生存:非主页业务尽量使用 router.replace 或在 onPageHide 时主动清理不再需要的缓存大图。