设计全局状态是大型 ArkTS 工程中最具挑战性的环节。由于 ArkTS 追求高性能、静态化和线程安全,它的全局状态设计与前端(如 Redux/Vuex)有显著差异。
以下是针对 ArkTS 的全局状态设计指南、风险分析及隔离方案。
1. 全局状态的三种设计模式
在 ArkTS 中,全局状态通常由以下三种层级构成:
A. AppStorage(系统级内置)
这是最直接的方案,由 HarmonyOS 运行时管理。
- 机制: 进程内唯一的单例中心,支持组件间的响应式链接。
- 适用场景: 跨 Ability 共享的极少数关键数据,如:登录 Token、用户偏好设置(深色模式)、全局字体大小。
- 代码示例:
AppStorage.setOrCreate('isLogin', true)。
B. 单例模式 + @Observed(工程化推荐)
这是目前大型 ArkTS 工程的主流方案。
- 机制: 在
Common模块中定义一个单例类,并使用@Observed装饰。 - 优点: 强类型约束、支持复杂对象逻辑、不依赖字符串 Key。
- 解耦: 配合
LocalStorage在页面树中按需注入。
C. PersistentStorage(持久化全局)
- 机制: 将
AppStorage的部分 Key 与磁盘文件关联。 - 适用场景: 需要跨进程启动保留的数据(如用户首次打开应用的引导状态)。
2. 什么是“状态污染”?如何发生?
在 ArkTS 中,状态污染主要体现在两个维度:逻辑污染和性能污染。
- Key 值冲突(逻辑污染):
AppStorage依赖字符串 Key。在多人协作的大型工程中,如果不加命名空间,Feature A 和 Feature B 可能会无意中修改同一个isBusy变量,导致难以排查的 UI 逻辑错误。 - 非预期全量重绘(性能污染): 如果你将一个包含 50 个字段的巨型 Object 存入
AppStorage,任何一个细小字段的改变都会导致所有连接到该对象的组件触发 Diff。 - 内存泄漏风险: 全局状态的生命周期是整个进程。如果将大量临时数据存入全局且不手动清理,内存占用会持续走高。
3. 如何实现模块隔离?
为了避免上述污染,大型工程必须通过**“物理隔离 + 逻辑网关”**实现状态模块化:
A. 基于共享包(HSP/HAR)的解耦
- 禁止直接暴露状态: 不要让 Feature 模块直接操作全局变量。
- 网关模式: 在 Feature 模块的
index.ets中导出一个StateBridge类。Feature 内部的状态对外部不可见,只暴露特定的方法进行修改。
B. 使用 LocalStorage 替代 AppStorage
- 核心策略: 尽量缩小状态的作用域。
- 实践: 一个 Feature 下的所有 Page 共享一个
LocalStorage实例。这个实例在进入 Feature 首页时创建,并在退出时随 UI 树自动销毁。这样可以确保状态不会“溢出”到其他业务模块。
C. 定义严格的 Namespace(命名空间)
如果必须使用 AppStorage,请建立统一的 Key 管理类:
TypeScript
// Common 层定义
export class GlobalStoreKey {
static readonly USER_INFO = "APP_MODULE_USER_INFO";
static readonly SETTINGS_THEME = "SETTING_MODULE_THEME";
}
4. 架构设计总结
| 维度 | 小型项目 | 大型工程 (推荐) |
|---|---|---|
| 存储位置 | 全量 AppStorage | LocalStorage (按模块) + AppStorage (极简) |
| 数据结构 | 简单对象 / 基础类型 | @Observed 装饰的 Class 单例 |
| 修改规范 | 随处修改 | 通过 Action/Service 方法统一修改 |
| 通信方式 | 强依赖状态变量 | Emitter (事件) + 路由参数 (Router) |
核心忠告: 在 ArkTS 中,全局状态越“瘦”越好。**“状态下沉、逻辑解耦”**是保证 HarmonyOS 应用长期运行不卡顿的关键。