OpenHarmony 全局全局状态管理 AppStorage + PersistentStorage 封装(API23)

发布时间:2026/7/21 15:06:17
OpenHarmony 全局全局状态管理 AppStorage + PersistentStorage 封装(API23) 摘要ArkUI 提供 AppStorage 内存全局状态、PersistentStorage 持久绑定存储两套全局状态方案原生零散使用存在问题全局 key 分散、无统一类型约束、状态变更监听冗余、持久化绑定重复编写、登录 / 深色模式 / 用户信息多状态混杂。本文封装统一全局状态管理类 GlobalStore集中管理全部全局变量、提供类型化读写、统一持久化绑定、批量监听状态变化、封装登录退出清空逻辑联动前文 Preferences 持久存储工具。API23 重构 AppStorage 响应式监听、持久化同步机制、页面销毁自动解绑监听修复多页面同时监听触发多次回调、持久化同步延迟、页面销毁监听残留内存泄漏等问题。关键词OpenHarmonyArkTSAPI23AppStoragePersistentStorage全局状态状态管理持久化状态一、引言1.1 原生全局状态开发痛点全局状态 Key 字符串硬编码分散在各个页面修改易漏改报错无 TS 类型约束存取全局变量全为 any无代码提示易传错值深色模式、登录状态、用户信息等需要持久化每个页面重复写 PersistentStorage 绑定多页面同时监听同一状态变更多次重复执行回调退出登录时需要逐个清空所有全局变量代码繁琐页面销毁未移除状态监听后台持续触发回调造成页面报错。1.2 两套核心 API 区分AppStorage内存全局状态整个应用单例共享重启 APP 丢失页面实时响应 State 同等响应式更新 UI。PersistentStorage桥接 AppStorage PreferencesAppStorage 变量变更自动写入本地持久化启动自动读取缓存回填。API23 状态管理核心升级PersistentStorage 同步写入优化状态修改立刻落盘不会重启丢失watch 监听支持页面生命周期自动解绑规避内存泄漏全局状态读写增加类型校验非法赋值抛出日志警告多页面同变量监听去重避免同一状态多次触发回调区分临时内存状态与持久化状态分开管理互不干扰。二、全局状态常量与类型定义 model/GlobalState.etsets// 全局状态唯一Key常量统一管理 export const GLOBAL_KEY { // 持久化状态重启保留 IS_LOGIN: isLogin, TOKEN: token, DARK_MODE: darkMode, LAST_ACCOUNT: lastAccount, // 临时内存状态重启清空 USER_INFO: userInfo, CUR_PAGE_INDEX: curPageIndex } // 用户信息类型 export interface UserInfo { userId: number userName: string avatar: string } // 全局状态完整类型约束 export interface GlobalStateType { [GLOBAL_KEY.IS_LOGIN]: boolean [GLOBAL_KEY.TOKEN]: string [GLOBAL_KEY.DARK_MODE]: boolean [GLOBAL_KEY.LAST_ACCOUNT]: string [GLOBAL_KEY.USER_INFO]: UserInfo | null [GLOBAL_KEY.CUR_PAGE_INDEX]: number }三、全局状态管理封装 utils/global_store.etsetsimport AppStorage from ohos.arkui.state.AppStorage import PersistentStorage from ohos.arkui.state.PersistentStorage import { GLOBAL_KEY, GlobalStateType, UserInfo } from ../model/GlobalState import LogUtil from ./log_util class GlobalStore { private static instance: GlobalStore // 存储页面监听映射页面销毁批量解绑 private watchMap: Mapstring, () void new Map() static getInstance(): GlobalStore { if (!GlobalStore.instance) { GlobalStore.instance new GlobalStore() } return GlobalStore.instance } // 初始化持久化绑定EntryAbility onCreate全局执行一次 initPersistentBind() { // 需要持久化的变量绑定本地Preferences PersistentStorage.link(GLOBAL_KEY.IS_LOGIN, false) PersistentStorage.link(GLOBAL_KEY.TOKEN, ) PersistentStorage.link(GLOBAL_KEY.DARK_MODE, false) PersistentStorage.link(GLOBAL_KEY.LAST_ACCOUNT, ) LogUtil.info(GlobalStore, 持久化全局状态绑定完成) } // 泛型读取全局状态 getT extends keyof GlobalStateType(key: T): GlobalStateType[T] { return AppStorage.GetGlobalStateType[T](key) } // 泛型写入全局状态 setT extends keyof GlobalStateType(key: T, value: GlobalStateType[T]) { const oldVal this.get(key) AppStorage.SetOrCreate(key, value) LogUtil.debug(GlobalStore, 状态变更 key:${key} 旧值:${oldVal} 新值:${value}) } // 监听状态变化返回解绑函数 watchT extends keyof GlobalStateType( key: T, callback: (newVal: GlobalStateType[T], oldVal: GlobalStateType[T]) void ): () void { const unWatch AppStorage.Watch(key, callback) // 存入监听池页面销毁统一释放 const watchId ${key}_${Date.now()} this.watchMap.set(watchId, unWatch) return () { unWatch() this.watchMap.delete(watchId) } } // 批量移除当前页面所有监听页面aboutToDisappear调用 clearPageWatch() { this.watchMap.forEach(unWatch unWatch()) this.watchMap.clear() LogUtil.debug(GlobalStore, 页面全局状态监听全部解绑) } // 登录赋值全套全局状态 setLogin(token: string, user: UserInfo, account: string) { this.set(GLOBAL_KEY.IS_LOGIN, true) this.set(GLOBAL_KEY.TOKEN, token) this.set(GLOBAL_KEY.USER_INFO, user) this.set(GLOBAL_KEY.LAST_ACCOUNT, account) } // 退出登录清空全部登录相关状态 logoutClear() { this.set(GLOBAL_KEY.IS_LOGIN, false) this.set(GLOBAL_KEY.TOKEN, ) this.set(GLOBAL_KEY.USER_INFO, null) LogUtil.info(GlobalStore, 执行退出登录清空用户全局状态) } // 切换深色模式 toggleDarkMode(val: boolean) { this.set(GLOBAL_KEY.DARK_MODE, val) } } export default GlobalStore.getInstance()四、配套初始化EntryAbility 全局一次性绑定持久化etsimport UIAbility from ohos.app.ability.UIAbility import GlobalStore from ../utils/global_store import LogUtil, { LogLevel } from ../utils/log_util import FileUtil from ../utils/file_util export default class EntryAbility extends UIAbility { onCreate() { const ctx this.context // 初始化底层工具上下文 FileUtil.setContext(ctx) LogUtil.setContext(ctx) // 生产环境屏蔽调试日志 LogUtil.setLevel(LogLevel.INFO) // 全局持久化状态绑定应用启动仅执行一次 GlobalStore.initPersistentBind() } }五、页面实战调用示例5.1 设置页深色模式切换监听etsimport GlobalStore from ../utils/global_store import { GLOBAL_KEY } from ../model/GlobalState Entry Component struct SettingPage { State dark: boolean false unWatch?: () void aboutToAppear() { // 读取全局深色模式 this.dark GlobalStore.get(GLOBAL_KEY.DARK_MODE) // 监听全局状态变化UI自动同步 this.unWatch GlobalStore.watch(GLOBAL_KEY.DARK_MODE, (newVal) { this.dark newVal }) } // 切换全局深色模式 changeDark(val: boolean) { GlobalStore.toggleDarkMode(val) } build() { Column() { Row() { Text(深色模式).layoutWeight(1).fontSize(18) Toggle({ isOn: this.dark }) .onChange((v: boolean) this.changeDark(v)) } } .width(100%) .height(100%) .backgroundColor(this.dark ? #121212 : #ffffff) } aboutToDisappear() { // 解绑当前页面所有状态监听防止内存泄漏 if (this.unWatch) this.unWatch() GlobalStore.clearPageWatch() } }5.2 登录页面登录写入全局状态etsimport GlobalStore from ../utils/global_store import RouterUtil from ../utils/router_util import { PAGE_ROUTE } from ../model/Constant import HttpUtil from ../utils/http_util Entry Component struct LoginPage { State account: string State pwd: string async submitLogin() { const res await HttpUtil.post{token:string, user:UserInfo}(/login, { username: this.account, password: this.pwd }) if (!res) return // 统一写入登录全套全局状态 GlobalStore.setLogin(res.data.token, res.data.user, this.account) // 跳转首页清空登录栈 RouterUtil.clearToIndex() } build() { Column() { TextInput({text:this.account, placeholder:账号}) TextInput({text:this.pwd, placeholder:密码, type:InputType.Password}) Button(登录).onClick(()this.submitLogin()) } } }5.3 个人中心页退出登录清空全局状态etsimport GlobalStore from ../utils/global_store import RouterUtil from ../utils/router_util import DialogUtil from ../utils/dialog_util Entry Component struct MinePage { build() { Column() { Button(退出登录) .onClick(() { DialogUtil.confirm({content:确定退出登录吗}, (){ // 清空登录全局状态 GlobalStore.logoutClear() // 跳转登录页清空路由栈 RouterUtil.clearAndLogin() }) }) } } }5.4 首页判断登录状态拦截路由etsimport GlobalStore from ../utils/global_store import { GLOBAL_KEY } from ../model/GlobalState import RouterUtil from ../utils/router_util // 跳转个人中心工具内置登录判断复用 function jumpMine() { const isLogin GlobalStore.get(GLOBAL_KEY.IS_LOGIN) if (!isLogin) { DialogUtil.alert({content:请先登录}) RouterUtil.push(PAGE_ROUTE.LOGIN) return } RouterUtil.push(PAGE_ROUTE.MINE, {}, true) }六、全局状态开发编码规范6.1 Key 管理规范所有全局变量统一存入GLOBAL_KEY常量禁止页面手写字符串 key区分持久化 / 临时内存状态分组便于维护新增全局状态必须同步更新GlobalStateType类型定义保证类型安全。6.2 持久化绑定规范PersistentStorage.link 仅在 EntryAbility.onCreate 全局执行一次仅用户配置、登录凭证等需要重启保留的变量开启持久化页面临时页面索引、弹窗临时标记等仅放内存不持久化。6.3 监听生命周期规范页面使用 watch 监听必须保存解绑函数aboutToDisappear 执行解绑调用 clearPageWatch 清除全部监听高频页面避免过多 watch 监听减少回调执行开销。6.4 登录状态规范登录统一调用 setLogin 批量赋值 token、用户信息、登录标记退出固定调用 logoutClear 一键清空全部登录相关状态路由、弹窗、接口请求全部读取 GlobalStore 判断登录统一数据源。6.5 UI 渲染规范页面 State 变量从 GlobalStore 读取初始值搭配 watch 同步更新禁止页面直接操作 AppStorage 原生 API全部通过 GlobalStore 封装方法读写。七、高频问题与解决方案问题 1重启 APP 深色模式、登录状态丢失 解决在 EntryAbility 初始化执行 PersistentStorage.link 绑定对应 key工具内部自动持久化同步。问题 2页面销毁后状态变更回调持续执行页面变量报错 解决页面销毁调用解绑函数 clearPageWatch 移除所有 watch 监听。问题 3多处页面修改 token代码分散难维护 解决统一封装 setLogin/logoutClear 方法集中管理登录相关全局变量。问题 4存取全局变量无代码提示容易传错类型 解决使用泛型 getT/setT配套 GlobalStateType 完整类型约束。问题 5升级 API23 后 PersistentStorage 同步延迟修改后立刻读取还是旧值 解决API23 优化自动同步机制link 绑定后 set 写入立即落盘无需手动 flush。八、总结GlobalStore 封装 ArkUI AppStorage PersistentStorage 全套全局状态能力统一管理全局 Key、类型约束、持久化绑定、状态监听、登录状态批量操作解决原生全局状态硬编码、无类型、监听泄漏、持久化重复绑定等工程化痛点。 全局仅在 EntryAbility 一次性初始化持久化绑定所有页面统一通过工具类读写状态完美联动前文路由拦截、登录校验、深色模式、Preferences 存储整套底层工具是鸿蒙项目跨页面共享数据标准解决方案适配 API23 分层 HAR/HSP 大型工程架构。