HarmonyOS应用开发实战:小事记 - Context 类层级体系:从 ApplicationContext 到 UIContext 的职责划分

前言
在 HarmonyOS 的 Stage 模型中,Context 是连接应用、模块、Ability 和 UI 层的核心纽带。每个组件都有其对应的 Context 类型,提供不同粒度的能力——从获取应用基本信息到启动其他 Ability,从资源管理到 UI 弹框控制。开发者如果混淆了不同 Context 的职责,轻则代码逻辑出错,重则出现运行时异常。本文以 小事记(xiaoshiji_ohos_app) 项目中的 EntryAbility.ets 和 SettingsPage.ets 为切入点,深入解析 ApplicationContext、UIAbilityContext、AbilityStageContext 和 UIContext 的继承关系、获取方式与最佳实践。
核心特点:
- 简单易用:API 设计直观,上手成本低
- 性能优异:底层优化充分,运行效率高
- 扩展性强:支持自定义配置和扩展
本文参考 HarmonyOS 官方文档:application-context-stage.md 和 UIAbility 参考。
一、Context 类的继承体系
1.1 类层级结构
HarmonyOS 的 Context 采用分层继承设计,每一层在基类基础上扩展特定能力:
Context(基类)
├── ApplicationContext(应用级别)
├── AbilityStageContext(模块级别)
├── UIAbilityContext(Ability 级别)
│ └── 通过 getHostContext() 获取
└── ExtensionContext(扩展能力级别)
├── BackupExtensionContext
├── ServiceExtensionContext
└── FormExtensionContext
UIContext 是独立的 UI 上下文,与上述继承体系无直接关系,它属于 ArkUI 框架的 UI 实例上下文。
| Context 类型 | 作用域 | 获取方式 | 关键能力 |
|---|---|---|---|
| Context(基类) | 全局 | 所有子类继承 | resourceManager、applicationInfo、area(文件分区) |
| ApplicationContext | 应用进程 | this.context.getApplicationContext() |
设置颜色模式、语言、监听前后台、清除数据 |
| AbilityStageContext | 模块 | AbilityStage 的 this.context |
获取模块信息、createModuleContext() |
| UIAbilityContext | Ability | UIAbility 的 this.context |
startAbility()、connectServiceExtensionAbility()、terminateSelf() |
| UIContext | UI 实例 | getUIContext() |
弹框、字体、键盘避让、获取宿主 Context |
1.2 不同类型 Context 不可互转
官方文档明确指出:不同类型的 Context 具有不同的能力,不可相互替代或强行转换。
// ❌ 错误:UIAbilityContext 没有 setFontSizeScale 方法
let uiAbilityContext = this.context as common.UIAbilityContext;
uiAbilityContext.setFontSizeScale(1.0); // 编译错误!
// ✅ 正确:先获取 ApplicationContext
let applicationContext = this.context.getApplicationContext();
applicationContext.setFontSizeScale(1.0, 1.0);
二、ApplicationContext:应用全局上下文
2.1 获取方式
ApplicationContext 是应用级别的全局上下文,在整个应用进程中唯一。官方提供了两种获取方式:
方式一:从 API 14 起,直接使用静态方法获取
import { application } from '@kit.AbilityKit';
let appContext = application.getApplicationContext();
方式二:通过已有的 Context 实例获取(兼容所有版本)
// 在 UIAbility 中获取
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
let appContext = this.context.getApplicationContext();
// 使用 ApplicationContext 设置颜色模式
appContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
}
}
2.2 核心能力详解
设置颜色模式 — 小事记项目在 onCreate 中调用了 setColorMode:
// EntryAbility.ets — 使用 ApplicationContext 设置颜色模式
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
try {
this.context.getApplicationContext().setColorMode(
ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET
);
} catch (err) {
hilog.error(DOMAIN, 'testTag',
'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
}
}
COLOR_MODE_NOT_SET 表示跟随系统设置,还有 COLOR_MODE_LIGHT(浅色)和 COLOR_MODE_DARK(深色)模式。
获取应用文件路径:
let appContext = this.context.getApplicationContext();
let filesDir = appContext.filesDir; // 应用文件目录
let cacheDir = appContext.cacheDir; // 缓存目录
let tempDir = appContext.tempDir; // 临时目录
监听应用前后台变化:
let appContext = this.context.getApplicationContext();
appContext.on('abilityLifecycle', (abilityLifecycleInfo) => {
if (abilityLifecycleInfo.lifecycleState === 'foreground') {
console.log('应用进入前台');
} else if (abilityLifecycleInfo.lifecycleState === 'background') {
console.log('应用进入后台');
}
});
设置应用语言:
appContext.setLanguage('zh-Hans-CN'); // 设置为简体中文
2.3 使用场景总结
| 场景 | 使用 ApplicationContext | 原因 |
|---|---|---|
| 设置颜色模式 | ✅ 必须使用 | 应用级配置,全局生效 |
| 设置语言 | ✅ 必须使用 | 应用级配置,全局生效 |
| 获取文件目录 | ✅ 推荐使用 | 路径与应用进程绑定 |
| 监听前后台 | ✅ 必须使用 | 只有 ApplicationContext 提供 on('abilityLifecycle') |
| 启动其他 Ability | ❌ 不可使用 | 需要 UIAbilityContext.startAbility() |
| 显示弹框 | ❌ 不可使用 | 需要 UIContext.showDialog() |
三、UIAbilityContext:Ability 级别上下文
3.1 获取方式
UIAbilityContext 是每个 UIAbility 实例独有的上下文,在 UIAbility 内部通过 this.context 直接获取:
// EntryAbility.ets — 直接访问 this.context
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// this.context 的类型是 UIAbilityContext
let abilityInfo = this.context.abilityInfo;
let hapModuleInfo = this.context.currentHapModuleInfo;
}
}
在 UI 组件中获取 UIAbilityContext,需要通过 UIContext.getHostContext():
// 在 @Component 中获取 UIAbilityContext
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct SettingsPage {
private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
build() {
Button('启动其他应用')
.onClick(() => {
this.context.startAbility({
bundleName: 'com.example.other',
abilityName: 'MainAbility'
});
})
}
}
3.2 核心能力详解
启动其他 Ability:
// 显式启动
this.context.startAbility({
bundleName: 'com.example.target',
abilityName: 'TargetAbility',
parameters: { key: 'value' }
});
// 隐式启动
this.context.startAbility({
action: 'ohos.want.action.view',
uri: 'https://developer.harmonyos.com'
});
连接 ServiceExtensionAbility:
let connectionId = this.context.connectServiceExtensionAbility(
{
bundleName: 'com.example.service',
abilityName: 'BackgroundService'
},
{
onConnect: (elementName, proxy) => {
console.log('Service 连接成功');
},
onDisconnect: () => {
console.log('Service 断开连接');
}
}
);
销毁自身:
this.context.terminateSelf((err) => {
if (err.code) {
console.error(`terminateSelf failed: ${err.message}`);
}
});
3.3 UIAbilityContext 与 ApplicationContext 的协作
实际开发中,两个 Context 经常配合使用:
// 在 UIAbility 中协作
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// UIAbilityContext — 记录启动参数
let abilityName = this.context.abilityInfo.name;
// ApplicationContext — 设置全局配置
let appContext = this.context.getApplicationContext();
appContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
}
四、AbilityStageContext:模块级别上下文
4.1 定义与获取
AbilityStage 是模块级别的生命周期入口,在 HAP 包加载时创建。它的 Context 是 AbilityStageContext,提供了模块级别的信息:
import { AbilityStage } from '@kit.AbilityKit';
export default class MyAbilityStage extends AbilityStage {
onCreate(): void {
// this.context 是 AbilityStageContext
let hapModuleInfo = this.context.currentHapModuleInfo;
console.log(`模块名称: ${hapModuleInfo.moduleName}`);
console.log(`模块描述: ${hapModuleInfo.description}`);
}
}
4.2 跨模块 Context 获取
在多 Module 工程中,可以通过 createModuleContext 获取其他模块的 Context:
// 获取其他 Module 的 Context
import { application } from '@kit.AbilityKit';
let moduleName = 'feature_module';
application.createModuleContext(this.context, moduleName)
.then((moduleContext: common.Context) => {
// 通过 moduleContext 访问该模块的资源
let resourceMgr = moduleContext.resourceManager;
})
.catch((err: BusinessError) => {
console.error(`获取模块 Context 失败: ${err.message}`);
});
提示:如果小事记项目后续扩展为多 Module 架构(如添加
share功能 HSP 模块),就需要通过createModuleContext来跨模块共享数据和资源。
五、UIContext:UI 实例上下文
5.1 与上述 Context 的本质区别
UIContext 不属于 Context 继承体系,它是 ArkUI 框架中的 UI 实例上下文,负责 UI 层面的操作。
| 对比维度 | Context 体系 | UIContext |
|---|---|---|
| 所属框架 | @kit.AbilityKit |
@kit.ArkUI |
| 作用范围 | 应用/模块/Ability 生命周期 | UI 实例/窗口级别 |
| 主要能力 | 启动 Ability、文件管理、资源管理 | 弹框、字体、键盘避让、动画 |
| 获取方式 | this.context 或 getHostContext() |
getUIContext() 或 window.getUIContext() |
5.2 获取方式
在 UI 组件中获取:
@Entry
@Component
struct HomePage {
build() {
Button('显示弹框')
.onClick(() => {
// 通过 getUIContext() 获取 UIContext
this.getUIContext().getPromptAction().showToast({
message: '操作成功',
duration: 2000
});
})
}
}
通过 Window 获取:
import { window } from '@kit.ArkUI';
// 在 UIAbility 中获取 Window 的 UIContext
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.getMainWindow().then((mainWindow) => {
let uiContext = mainWindow.getUIContext();
// 使用 UIContext
});
}
5.3 核心能力详解
显示弹框与提示:
let uiContext = this.getUIContext();
// Toast 提示
uiContext.getPromptAction().showToast({ message: '保存成功', duration: 2000 });
// 确认对话框
uiContext.getPromptAction().showDialog({
title: '提示',
text: '确定要删除这条记录吗?',
buttons: [
{ text: '取消', color: '#9CA3AF' },
{ text: '确定', color: '#FF6B6B' }
]
});
// 操作菜单
uiContext.getPromptAction().showActionMenu({
title: '请选择操作',
buttons: [
{ text: '编辑', color: '#7B68EE' },
{ text: '删除', color: '#FF6B6B' }
]
});
获取宿主 Context:
// 在 UI 组件中获取 UIAbilityContext
let uiAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
设置键盘避让模式:
this.getUIContext().setKeyboardAvoidMode(
KeyboardAvoidMode.RESIZE // 键盘弹出时应用窗口向上避让
);
六、实际项目中的 Context 使用模式
6.1 小事记项目的 Context 使用分析
在 EntryAbility.ets 中,使用了两种 Context 的协作:
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 1. 使用 UIAbilityContext(this.context)获取 ApplicationContext
let appContext = this.context.getApplicationContext();
// 2. 使用 ApplicationContext 设置颜色模式
appContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
// 3. 使用 UIAbilityContext 记录日志信息
hilog.info(DOMAIN, 'testTag', 'Ability onCreate');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// 4. 使用 WindowStage 加载页面
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(DOMAIN, 'testTag',
'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
return;
}
});
}
}
Context 的职责流转过程如下:
用户点击应用图标
↓
系统创建 UIAbility 实例
↓
this.context = UIAbilityContext ← Ability 级别的上下文
↓
this.context.getApplicationContext() → ApplicationContext ← 应用级别的上下文
↓
onWindowStageCreate(windowStage) → WindowStage ← 窗口管理
↓
windowStage.loadContent('pages/Index') → 加载 UI 页面
↓
在 UI 组件中 getUIContext() → UIContext ← UI 实例上下文
6.2 推荐的 Context 获取策略
| 代码位置 | 推荐的 Context 获取方式 | 原因 |
|---|---|---|
| UIAbility 内部 | 直接使用 this.context |
类型为 UIAbilityContext,功能最全 |
| UIAbility 内部(应用级操作) | this.context.getApplicationContext() |
获取应用级能力 |
| AbilityStage 内部 | this.context(类型为 AbilityStageContext) |
模块级操作 |
| @Component 组件(UI 操作) | this.getUIContext() |
直接访问 UI 相关 API |
| @Component 组件(Ability 操作) | this.getUIContext().getHostContext() |
获取 UIAbilityContext |
| ExtensionAbility 内部 | this.context(类型为 ExtensionContext) |
扩展能力上下文 |
6.3 常见错误与避免
错误 1:在 UI 组件中直接使用 UIAbility 的 this.context
// ❌ 错误:UI 组件中没有 this.context
@Entry
@Component
struct HomePage {
aboutToAppear(): void {
let appContext = this.context.getApplicationContext(); // 编译错误!
}
}
// ✅ 正确:通过 UIContext 获取宿主 Context
@Entry
@Component
struct HomePage {
private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
aboutToAppear(): void {
let appContext = this.context.getApplicationContext(); // 正确
}
}
错误 2:混淆 UIContext 与 ApplicationContext
// ❌ 错误:UIContext 没有 setLanguage 方法
let uiContext = this.getUIContext();
uiContext.setLanguage('zh-Hans-CN'); // 编译错误!
// ✅ 正确:获取 ApplicationContext 后调用
let appContext = this.getUIContext().getHostContext()
.getApplicationContext();
appContext.setLanguage('zh-Hans-CN');
七、Context 在性能与内存中的考量
7.1 Context 的引用传递
Context 持有与泄露是常见的内存问题。ApplicationContext 是单例的,而 UIAbilityContext 在 Ability 销毁后应被释放:
// ❌ 错误:在全局单例中持有 UIAbilityContext
class GlobalManager {
static context: UIAbilityContext; // 可能造成泄露
}
// ✅ 正确:使用 ApplicationContext 进行全局存储
class GlobalManager {
static context: ApplicationContext; // 应用级别,不会泄露
}
7.2 Context 的等价性判断
由于 Context 存在继承关系,判断两个 Context 是否相等时需要注意:
// 两个不同的 UIAbility 实例,它们的 context 不同
let context1 = ability1.context;
let context2 = ability2.context;
console.log(context1 === context2); // false
// 但 getApplicationContext() 返回的是同一个对象
let appContext1 = ability1.context.getApplicationContext();
let appContext2 = ability2.context.getApplicationContext();
console.log(appContext1 === appContext2); // true(单例)
八、实战:在 SettingsPage 中管理 Context
8.1 场景描述
在小事记的 SettingsPage.ets 中,需要实现以下功能:
- 读取用户配置(需要 ApplicationContext 获取文件路径)
- 跳转到数据备份页面(需要 UIAbilityContext 启动 Ability)
- 显示提示弹框(需要 UIContext)
8.2 完整实现
// SettingsPage.ets — 三种 Context 的协作使用
import router from '@ohos.router';
import { common } from '@kit.AbilityKit';
import { BottomTabBar } from '../common/BottomTabBar';
@Entry
@Component
export struct SettingsPage {
// 获取 UIAbilityContext(用于启动 Ability)
private uiAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
// 获取 ApplicationContext(用于文件操作)
private appContext = this.uiAbilityContext.getApplicationContext();
build() {
Column() {
// 设置页面 UI
Scroll() {
Column({ space: 16 }) {
this.buildSettingsCard('data')
}
.padding({ bottom: 20 })
}
.layoutWeight(1)
BottomTabBar({ currentTab: 'SettingsPage' })
}
.width('100%')
.height('100%')
.backgroundColor('#F8F9FA')
}
@Builder
buildSettingsCard(group: string) {
Column({ space: 0 }) {
if (group === 'data') {
Row() {
Text('数据备份')
Blank()
Text('>')
}
.height(52)
.padding({ left: 20, right: 20 })
.onClick(() => {
// 使用 UIAbilityContext 的路由能力
router.pushUrl({ url: 'pages/DataBackupPage' });
})
}
}
.backgroundColor(Color.White)
.borderRadius(16)
.margin({ left: 20, right: 20 })
}
}
总结
本文从 xiaoshiji_ohos_app 项目的源码出发,深入解析了 HarmonyOS Stage 模型中 Context 类层级体系 的设计与使用。核心要点如下:
- Context 体系分为五层:基类 Context → ApplicationContext / AbilityStageContext / UIAbilityContext / ExtensionContext,各层职责分明,不可互转
- UIContext 是独立的 UI 上下文,不属于 Context 继承体系,专用于 UI 操作(弹框、字体、键盘避让)
- 获取策略:UIAbility 中直接使用
this.context,UI 组件中通过getUIContext().getHostContext()获取 Ability 上下文 - 内存管理:ApplicationContext 是单例安全的,而 UIAbilityContext 在 Ability 销毁后应被释放,避免在全局单例中持有
下一篇文章将深入解析 module.json5 配置,详解 Ability 声明、skills 隐式匹配和 extensionAbilities 的配置技巧。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- 小事记项目源码:xiaoshiji_ohos_app
- 官方文档 - 应用上下文 Context:application-context-stage.md
- 官方文档 - UIAbility 参考:js-apis-app-ability-uiability
- 官方文档 - ApplicationContext:js-apis-inner-application-applicationcontext
- 官方文档 - UIContext:arkts-apis-uicontext-uicontext
- 官方文档 - 应用生命周期:application-lifecycle.md
- 官方文档 - Context 获取示例:application-context-stage
- 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)