一个应用只有一个 entry HAP 还好说,一旦拆成 entry + 多个 feature HAP,每个模块怎么初始化?数据库在哪个时机打开?资源预加载在哪里做?答案就是 AbilityStage——HAP 级别的"Application",每个 HAP 加载时第一个触发的生命周期。这篇把 AbilityStage 的所有回调和多 HAP 管理讲清楚。

AbilityStage 是什么

如果把 UIAbility 比作 Activity,那 AbilityStage 就是每个 HAP 的 Application:

对比 Application AbilityStage
作用域 整个应用 单个 HAP
触发时机 应用启动 HAP 首次加载
数量 1 个 每个 HAP 1 个
主要用途 全局初始化 模块级初始化
import { AbilityStage, AbilityConstant, Want, Configuration } from '@kit.AbilityKit'

在这里插入图片描述

创建 AbilityStage

1. 实现 AbilityStage 类

// entry/src/main/ets/myabilitystage/MyAbilityStage.ets
export default class MyAbilityStage extends AbilityStage {
  onCreate(): void {
    console.info('MyAbilityStage onCreate')
    // 模块级初始化:数据库、网络、资源预加载
    this.initModuleResources()
  }

  onAcceptWant(want: Want): string {
    // specified 模式下返回实例标识
    if (want.action === 'action.share') {
      return 'share_instance_' + want.parameters?.deviceId
    }
    return ''
  }

  onConfigurationUpdate(newConfig: Configuration): void {
    console.info('onConfigurationUpdate: ' + JSON.stringify(newConfig))
    // 语言/深浅色变更时更新模块资源
  }

  onMemoryLevel(level: AbilityConstant.MemoryLevel): void {
    console.info('onMemoryLevel: ' + level)
    // 根据内存级别释放非必要资源
    if (level === AbilityConstant.MemoryLevel.MEMORY_LEVEL_CRITICAL) {
      this.releaseCache()
    }
  }

  private initModuleResources(): void {
    // 初始化数据库连接
    // 预加载配置数据
    // 注册模块事件监听
  }

  private releaseCache(): void {
    // 释放图片缓存
    // 清理临时数据
  }
}

2. 在 module.json5 中注册

{
  "module": {
    "name": "entry",
    "type": "entry",
    "srcEntry": "./ets/myabilitystage/MyAbilityStage.ets",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets"
      }
    ]
  }
}

要点: srcEntry 指定 AbilityStage 脚本路径。HAP 首次加载时,系统先创建 AbilityStage(触发 onCreate),再创建 UIAbility。

四大回调详解

onCreate——模块初始化

HAP 加载时触发,是最早的初始化时机。

onCreate(): void {
  // 适合做的事:
  // 1. 初始化模块数据库
  // 2. 预加载配置数据
  // 3. 注册全局事件监听
  // 4. 初始化网络SDK

  // 不适合做的事:
  // 1. 耗时操作(会阻塞 HAP 加载)
  // 2. UI 操作(此时还没 UI)
  // 3. 路由跳转(Ability 还没创建)
}

要点: onCreate 只在 HAP 首次加载时触发一次,不会重复触发。如果 HAP 已经加载过,后续启动 Ability 不会再触发 onCreate。

onAcceptWant——specified 模式实例标识

当 UIAbility 的 launchType 为 specified 时,系统通过 onAcceptWant 返回的字符串决定复用还是新建实例。

onAcceptWant(want: Want): string {
  // 返回空字符串 → 每次新建实例
  // 返回相同字符串 → 复用已有实例

  if (want.action === 'action.document.edit') {
    let docId: string = want.parameters?.docId as string
    return 'doc_' + docId  // 同一文档复用同一实例
  }

  if (want.action === 'action.contact.detail') {
    let contactId: string = want.parameters?.contactId as string
    return 'contact_' + contactId
  }

  return ''
}

要点: onAcceptWant 只对 specified 启动模式生效。返回的字符串就是实例的"身份证",相同身份证复用实例,不同身份证新建实例。

onConfigurationUpdate——配置变更

系统语言、深浅色、字体大小等配置变更时触发。

onConfigurationUpdate(newConfig: Configuration): void {
  if (newConfig.language !== undefined) {
    // 语言变更,重新加载多语言资源
    this.reloadI18nResources(newConfig.language)
  }

  if (newConfig.colorMode !== undefined) {
    // 深浅色切换
    if (newConfig.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
      this.applyDarkTheme()
    } else {
      this.applyLightTheme()
    }
  }
}

要点: Configuration 包含 language、colorMode、fontSize 等字段。不是每个字段每次都会变,检查 undefined 判断哪个配置变了。

onMemoryLevel——内存告警

系统内存紧张时触发,按级别释放资源。

onMemoryLevel(level: AbilityConstant.MemoryLevel): void {
  // MEMORY_LEVEL_MODERATE = 0  → 适度释放
  // MEMORY_LEVEL_LOW = 1       → 释放较多缓存
  // MEMORY_LEVEL_CRITICAL = 2  → 释放所有非必要资源

  if (level >= AbilityConstant.MemoryLevel.MEMORY_LEVEL_LOW) {
    // 清理图片缓存
    // 释放临时数据
    // 关闭非活跃连接
  }

  if (level === AbilityConstant.MemoryLevel.MEMORY_LEVEL_CRITICAL) {
    // 释放所有可释放资源
    // 保存关键数据
    // 准备被系统回收
  }
}

要点: 内存级别从 MODERATE → LOW → CRITICAL 递增。收到 CRITICAL 时要立即释放资源,否则系统可能直接杀进程。

多 HAP 场景:每个模块独立初始化

大型应用拆成多个 HAP 后,每个 HAP 有自己的 AbilityStage:

MyApp/
├── entry/          → EntryAbilityStage (全局数据库、账号)
│   └── srcEntry: ./ets/EntryAbilityStage.ets
├── share/          → ShareAbilityStage (分享SDK初始化)
│   └── srcEntry: ./ets/ShareAbilityStage.ets
└── payment/        → PaymentAbilityStage (支付SDK初始化)
    └── srcEntry: ./ets/PaymentAbilityStage.ets
// entry 模块的 AbilityStage
export default class EntryAbilityStage extends AbilityStage {
  onCreate(): void {
    // 初始化全局数据库
    // 检查登录态
    // 预加载首页数据
  }
}

// share 模块的 AbilityStage
export default class ShareAbilityStage extends AbilityStage {
  onCreate(): void {
    // 初始化分享SDK
    // 注册分享平台
  }
}

// payment 模块的 AbilityStage
export default class PaymentAbilityStage extends AbilityStage {
  onCreate(): void {
    // 初始化支付SDK
    // 加载商品配置
  }
}

要点: feature HAP 的 AbilityStage 在该 HAP 首次被访问时才触发 onCreate,实现了按需初始化——不用就不加载,省内存省启动时间。

specified 启动模式与 onAcceptWant 配合

三种启动模式对比:

启动模式 实例数量 onAcceptWant 适用场景
singleton 1 个 不触发 全局唯一(主页、设置)
multiton 多个 不触发 每次启动新建(已废弃)
specified 按需 触发 同标识复用(文档编辑)
// module.json5
{
  "abilities": [
    {
      "name": "DocumentAbility",
      "launchType": "specified"
    }
  ]
}
// AbilityStage.onAcceptWant
onAcceptWant(want: Want): string {
  // 打开文档A → 返回 'doc_A' → 复用已有 doc_A 实例
  // 打开文档B → 返回 'doc_B' → 没有 doc_B 实例,新建
  let docId: string = want.parameters?.docId as string
  return 'doc_' + docId
}

完整 Demo 代码

Demo 模拟了 AbilityStage 生命周期回调和多 HAP 模块加载过程。

interface StageEvent {
  name: string;
  time: string;
  detail: string;
}

interface ModuleInfo {
  name: string;
  type: string;
  stageReady: boolean;
  abilities: string[];
}

@Entry
@Component
struct AbilityStageDemo {
  @State stageLog: StageEvent[] = [];
  @State moduleList: ModuleInfo[] = [];
  @State currentPhase: string = '';
  @State memoryLevel: string = '正常';

  aboutToAppear(): void {
    this.moduleList = [
      { name: 'entry', type: 'entry', stageReady: true, abilities: ['EntryAbility'] },
      { name: 'share', type: 'feature', stageReady: false, abilities: ['ShareAbility'] },
      { name: 'payment', type: 'feature', stageReady: false, abilities: ['PayAbility'] }
    ];
  }

  build() {
    Column({ space: 0 }) {
      Row() {
        Button('< 返回')
          .fontSize(14)
          .backgroundColor(Color.Transparent)
          .fontColor('#1a73e8')
          .onClick(() => { router.back(); })
        Text('AbilityStage 初始化')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .layoutWeight(1)
          .textAlign(TextAlign.Center)
        Text(this.memoryLevel)
          .fontSize(12)
          .fontColor(this.memoryLevel === '正常' ? '#4CAF50' : '#F44336')
      }
      .width('100%')
      .height(56)
      .padding({ left: 12, right: 12 })
      .alignItems(VerticalAlign.Center)
      .backgroundColor('#FFFFFF')

      Scroll() {
        Column({ space: 16 }) {
          Column({ space: 12 }) {
            Text('AbilityStage 生命周期')
              .fontSize(16)
              .fontWeight(FontWeight.Bold)
              .width('100%')

            Row({ space: 8 }) {
              Button('onCreate').onClick(() => this.simulateEvent('onCreate', 'HAP加载,初始化资源'))
              Button('onAcceptWant').onClick(() => this.simulateEvent('onAcceptWant', 'specified模式返回Key'))
              Button('onConfigUpdate').onClick(() => this.simulateEvent('onConfigurationUpdate', '语言/深浅色变更'))
              Button('onMemoryLevel').onClick(() => this.simulateEvent('onMemoryLevel', '系统内存告警'))
            }
          }
          .width('100%')
          .padding(16)
          .borderRadius(12)
          .backgroundColor('#FFFFFF')

          Column({ space: 12 }) {
            Text('多HAP模块管理')
              .fontSize(16)
              .fontWeight(FontWeight.Bold)
              .width('100%')

            ForEach(this.moduleList, (mod: ModuleInfo) => {
              Row({ space: 12 }) {
                Column()
                  .width(8)
                  .height(8)
                  .borderRadius(4)
                  .backgroundColor(mod.stageReady ? '#4CAF50' : '#E0E0E0')
                Column({ space: 2 }) {
                  Text(mod.name).fontSize(15).fontWeight(FontWeight.Medium)
                  Text(`类型: ${mod.type} | Ability: ${mod.abilities.join(', ')}`)
                    .fontSize(12).fontColor('#999999')
                }
                .layoutWeight(1)
                .alignItems(HorizontalAlign.Start)
                Text(mod.stageReady ? '已加载' : '未加载')
                  .fontSize(12)
                  .fontColor(mod.stageReady ? '#4CAF50' : '#999999')
                Button('加载')
                  .fontSize(12).height(28).enabled(!mod.stageReady)
                  .onClick(() => {
                    mod.stageReady = true;
                    this.simulateEvent('onCreate', `${mod.name}模块加载`);
                  })
              }
              .width('100%')
              .padding(12)
              .borderRadius(8)
              .backgroundColor('#FAFAFA')
            }, (mod: ModuleInfo) => mod.name)
          }
          .width('100%')
          .padding(16)
          .borderRadius(12)
          .backgroundColor('#FFFFFF')

          if (this.stageLog.length > 0) {
            Column({ space: 8 }) {
              Row() {
                Text(`生命周期日志 (${this.stageLog.length})`)
                  .fontSize(16).fontWeight(FontWeight.Bold).layoutWeight(1)
                Button('清除').fontSize(12).height(28)
                  .onClick(() => { this.stageLog = []; })
              }
              ForEach(this.stageLog.slice().reverse(), (event: StageEvent) => {
                Row({ space: 8 }) {
                  Text(event.time).fontSize(11).fontColor('#999999').width(60)
                  Text(event.name).fontSize(13).fontWeight(FontWeight.Medium)
                    .fontColor(this.getEventColor(event.name)).width(110)
                  Text(event.detail).fontSize(12).fontColor('#666666').layoutWeight(1)
                }
                .width('100%').padding(4)
              }, (event: StageEvent, index: number) => `${index}`)
            }
            .width('100%')
            .padding(16)
            .borderRadius(12)
            .backgroundColor('#FFFFFF')
          }
        }
        .padding(16)
      }
      .layoutWeight(1)
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }

  private simulateEvent(name: string, detail: string): void {
    this.currentPhase = name
    this.stageLog.push({
      name: name,
      time: new Date().toLocaleTimeString(),
      detail: detail
    })
    if (name === 'onMemoryLevel') {
      this.memoryLevel = '内存紧张'
      setTimeout(() => { this.memoryLevel = '正常'; }, 3000)
    }
  }

  private getEventColor(name: string): string {
    if (name === 'onCreate') return '#1565C0'
    if (name === 'onAcceptWant') return '#2E7D32'
    if (name === 'onConfigurationUpdate') return '#E65100'
    if (name === 'onMemoryLevel') return '#C62828'
    return '#333333'
  }
}

Application vs AbilityStage 初始化分工

初始化内容 放 Application 放 AbilityStage
全局数据库
账号/登录态
模块数据库
SDK 初始化 ✓(按模块)
资源预加载 ✓(按需)
网络全局配置
模块路由表

要点: 全局共享的放 Application,模块独有的放 AbilityStage。避免在 Application 里做所有初始化——feature HAP 没加载就白初始化了。

踩坑清单

问题 原因 解决
onCreate 不触发 module.json5 未配置 srcEntry 添加 srcEntry 字段
onAcceptWant 不触发 UIAbility launchType 不是 specified 改为 specified 模式
specified 模式每次都新建 onAcceptWant 返回空字符串 返回唯一标识字符串
配置变更不回调 未实现 onConfigurationUpdate 实现 onConfigurationUpdate
内存告警不回调 系统内存还够 模拟器上难触发,真机低内存测试
HAP 加载慢 onCreate 里做耗时操作 耗时操作放 Worker 或延迟执行
多 HAP 共享数据库冲突 两个 HAP 同时初始化 放到 Application 全局初始化一次
AbilityStage 引用不到 context onCreate 里 this.context 可能为空 用 UIAbility 的 context 替代
feature HAP onCreate 时机不确定 按需加载 首次打开该模块 Ability 时触发
onCreate 和 Ability.onCreate 顺序 Stage 先于 Ability 依赖 Ability 的逻辑不要放 Stage
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐