新手学鸿蒙——UIAbility组件深度解析

前言

在上一篇《应用架构设计原则》中,我们初步了解了 UIAbility 的概念。本文将深入探讨 UIAbility 组件的方方面面,包括生命周期管理、启动模式、跨 Ability 通信等核心技能。

学习目标:掌握 UIAbility 的完整开发能力,能够独立设计多 Ability 应用架构。


一、UIAbility 是什么?

1.1 定义

UIAbility 是 HarmonyOS 应用中负责界面展示和用户交互的核心组件。可以类比为 Android 的 Activity 或 iOS 的 ViewController,但能力更强大。

1.2 核心职责

职责 说明
界面管理 加载页面、管理窗口
生命周期 处理创建、前后台切换、销毁等事件
用户交互 响应用户操作,处理输入事件
数据传递 接收启动参数,返回处理结果
资源管理 申请和释放系统资源

二、生命周期回调详解

2.1 完整生命周期流程

应用启动
    ↓
┌─────────────┐
│  onCreate   │  初始化数据、恢复状态
└──────┬──────┘
       ↓
┌──────────────────┐
│onWindowStageCreate│  创建窗口、设置UI内容
└──────┬───────────┘
       ↓
┌──────────────┐
│ onForeground │  获取焦点、恢复动画
└──────┬───────┘
       ↓
    【用户交互】
       ↓
┌──────────────┐
│ onBackground │  暂停动画、保存临时数据
└──────┬───────┘
       ↓
┌───────────────────┐
│onWindowStageDestroy│  释放窗口资源
└──────┬────────────┘
       ↓
┌─────────────┐
│  onDestroy  │  释放所有资源
└─────────────┘

2.2 回调方法详解

onCreate()

触发时机:Ability 首次创建时调用,整个生命周期只调用一次。

使用场景

  • 初始化全局变量
  • 恢复持久化数据
  • 注册全局监听器
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';

export default class MainAbility extends UIAbility {
  // 全局变量
  private userData: any = null;

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    console.log('[MainAbility] onCreate');

    // 恢复用户数据
    const savedData = want.parameters?.userData;
    if (savedData) {
      this.userData = JSON.parse(savedData as string);
      console.log('恢复用户数据:', this.userData);
    }

    // 初始化全局状态
    this.initGlobalState();
  }

  private initGlobalState(): void {
    // 初始化全局状态管理
    console.log('初始化全局状态');
  }
}
onWindowStageCreate()

触发时机:WindowStage 创建完成后调用。

使用场景

  • 设置主窗口内容
  • 加载初始页面
  • 配置窗口属性
import window from '@ohos.window';

onWindowStageCreate(windowStage: window.WindowStage): void {
  console.log('[MainAbility] onWindowStageCreate');

  // 1. 设置窗口全屏
  windowStage.getMainWindow().then((win) => {
    win.setWindowLayoutFullScreen(true);
  });

  // 2. 加载主页面
  windowStage.loadContent('pages/Index', (err, data) => {
    if (err.code) {
      console.error('加载页面失败:', err.message);
      return;
    }
    console.log('加载页面成功');
  });
}
onForeground()

触发时机:Ability 从后台切换到前台,用户可见。

使用场景

  • 恢复动画
  • 重新连接网络
  • 刷新数据
onForeground(): void {
  console.log('[MainAbility] onForeground');

  // 恢复动画
  this.resumeAnimation();

  // 刷新数据
  this.refreshData();
}

private resumeAnimation(): void {
  console.log('恢复动画播放');
}

private refreshData(): void {
  console.log('刷新页面数据');
  // 调用 API 刷新数据
}
onBackground()

触发时机:Ability 从前台切换到后台,用户不可见。

使用场景

  • 暂停动画
  • 保存临时数据
  • 释放部分资源
onBackground(): void {
  console.log('[MainAbility] onBackground');

  // 暂停动画节省性能
  this.pauseAnimation();

  // 保存临时数据
  this.saveTempData();
}

private pauseAnimation(): void {
  console.log('暂停动画播放');
}

private saveTempData(): void {
  console.log('保存临时数据');
  // 使用 Preferences 保存临时数据
}
onDestroy()

触发时机:Ability 销毁时调用。

使用场景

  • 释放资源
  • 取消监听器
  • 保存持久化数据
onDestroy(): void {
  console.log('[MainAbility] onDestroy');

  // 取消网络请求
  this.cancelNetworkRequests();

  // 释放资源
  this.releaseResources();
}

private cancelNetworkRequests(): void {
  console.log('取消所有网络请求');
}

private releaseResources(): void {
  console.log('释放资源');
}

三、启动模式深度解析

3.1 multiton 模式(默认)

特点:每次启动都创建新实例。

配置方式

// module.json5
{
  "module": {
    "abilities": [
      {
        "name": "DetailAbility",
        "launchType": "multiton"
      }
    ]
  }
}

应用场景

  • 详情页(每次打开不同商品详情)
  • 聊天会话页
  • 浏览器标签页

实例

用户操作序列:
1. 打开商品A详情 → 创建 DetailAbility 实例1
2. 打开商品B详情 → 创建 DetailAbility 实例2
3. 打开商品C详情 → 创建 DetailAbility 实例3

结果:同时存在3个 DetailAbility 实例

3.2 singleton 模式

特点:全局唯一实例,每次启动复用同一实例。

配置方式

{
  "abilities": [
    {
      "name": "MainAbility",
      "launchType": "singleton"
    }
  ]
}

应用场景

  • 主页面
  • 设置页面
  • 个人中心

实例

用户操作序列:
1. 启动应用 → 创建 MainAbility 实例
2. 跳转详情页
3. 返回主页 → 复用 MainAbility 实例

结果:始终只有一个 MainAbility 实例

3.3 specified 模式

特点:根据指定的 Key 决定是否创建新实例。

使用场景:多账号、多窗口等复杂场景。

配置方式

{
  "abilities": [
    {
      "name": "ChatAbility",
      "launchType": "specified"
    }
  ]
}

代码实现

// 启动方代码
import common from '@ohos.app.ability.common';

// 启动指定的聊天会话
startChat(contactId: string) {
  const context = getContext(this) as common.UIAbilityContext;

  const want: Want = {
    bundleName: 'com.example.chat',
    abilityName: 'ChatAbility',
    parameters: {
      // 指定实例的唯一标识
      'instanceKey': contactId
    }
  };

  context.startAbility(want);
}
// ChatAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility';

export default class ChatAbility extends UIAbility {
  // 必须实现此方法
  onAcceptWant(want: Want): string {
    // 返回实例标识
    return want.parameters?.instanceKey as string;
  }
}

效果

启动序列:
1. 启动聊天会话 user_001 → 创建实例 user_001
2. 启动聊天会话 user_002 → 创建实例 user_002
3. 再次启动聊天会话 user_001 → 复用实例 user_001

结果:2个实例(user_001 和 user_002)

四、UIAbility 之间的数据传递

4.1 启动 Ability 并传递参数

发送方

import common from '@ohos.app.ability.common';
import Want from '@ohos.app.ability.Want';

// 启动详情页并传递商品ID
function openDetailPage(productId: string) {
  const context = getContext(this) as common.UIAbilityContext;

  const want: Want = {
    bundleName: 'com.example.myapp',
    abilityName: 'DetailAbility',
    parameters: {
      'productId': productId,
      'source': 'home'
    }
  };

  context.startAbility(want)
    .then(() => {
      console.log('启动详情页成功');
    })
    .catch((err: Error) => {
      console.error('启动详情页失败:', err.message);
    });
}

接收方

import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';

export default class DetailAbility extends UIAbility {
  private productId: string = '';

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // 接收传递过来的参数
    this.productId = want.parameters?.productId as string;
    console.log('商品ID:', this.productId);
  }
}

4.2 启动 Ability 并获取返回结果

调用方

async function openSettings(): Promise<void> {
  const context = getContext(this) as common.UIAbilityContext;

  const result = await context.startAbilityForResult({
    bundleName: 'com.example.myapp',
    abilityName: 'SettingsAbility'
  });

  if (result.resultCode === 0) {
    console.log('返回数据:', result.want?.parameters);
  }
}

被调用方

function saveAndReturn(): void {
  this.context.terminateSelfWithResult({
    resultCode: 0,
    want: {
      parameters: { 'themeChanged': true }
    }
  });
}

五、实战案例:登录状态管理

完整实现登录功能,包含:

  • 未登录跳转登录页
  • 登录成功返回主页
  • 登录信息全局共享

详细代码已在本文提供,请参考上文。


六、常见问题 FAQ

Q1:UIAbility 和 Page 有什么区别?

UIAbility 是应用级组件,Page 是页面级组件。普通页面跳转使用 Page。

Q2:什么时候创建新 UIAbility?

需要独立启动入口或隔离生命周期时创建。

Q3:如何共享数据?

使用 AppStorage、Preferences 或数据库。


七、总结

本文要点:

  • ✅ UIAbility 生命周期管理
  • ✅ 三种启动模式详解
  • ✅ Ability 间数据传递
  • ✅ 登录状态管理实战

下一篇预告:《新手学鸿蒙——应用进程与线程模型》

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐