2-19.【ArkTS】全局状态在 ArkTS 中如何设计?是否存在状态污染?如何做模块隔离?

0 阅读3分钟

设计全局状态是大型 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. 架构设计总结

维度小型项目大型工程 (推荐)
存储位置全量 AppStorageLocalStorage (按模块) + AppStorage (极简)
数据结构简单对象 / 基础类型@Observed 装饰的 Class 单例
修改规范随处修改通过 Action/Service 方法统一修改
通信方式强依赖状态变量Emitter (事件) + 路由参数 (Router)

核心忠告: 在 ArkTS 中,全局状态越“瘦”越好。**“状态下沉、逻辑解耦”**是保证 HarmonyOS 应用长期运行不卡顿的关键。