文章目录
- 前言
- 一、HarmonyOS 的状态管理层级
- 二、AppStorage 的基本操作
- 2.1 写入数据(在 EntryAbility 里)
- 2.2 在组件中读取:@StorageProp
- 2.3 双向同步:@StorageLink
- 三、为什么用 AppStorage 而不是普通全局变量?
- 四、数据流向图
- 五、完整使用示例
- 六、AppStorage 的注意事项
- 6.1 Key 命名要规范
- 6.2 值类型要一致
- 6.3 App 重启后数据丢失
- 七、@State vs @StorageProp 怎么选?
- 总结
前言
上一篇我们看到,EntryAbility把状态栏高度存进了AppStorage,然后GasStationPage用@StorageProp读出来。
不传参、不用全局变量,两个毫不相干的地方就完成了数据共享——这就是AppStorage的魔力。这篇文章把 HarmonyOS 的状态管理体系从头讲清楚。
项目预览
一、HarmonyOS 的状态管理层级
HarmonyOS 的状态管理分三个层级:
AppStorage(应用级) ↕ 双向同步 └─ @StorageProp / @StorageLink(页面/组件访问 AppStorage) PersistentStorage(持久化) └─ 数据写入磁盘,App 重启后保留 LocalStorage(页面级) └─ 页面内或页面树内共享,比 AppStorage 范围小| 存储类型 | 作用范围 | 是否持久化 | 典型用途 |
|---|---|---|---|
@State | 单个组件内部 | 否 | 组件自身的 UI 状态 |
LocalStorage | 页面内部或子树 | 否 | 同一页面的多组件共享 |
AppStorage | 整个应用(全局) | 否(App关闭丢失) | 全局配置、运行时数据 |
PersistentStorage | 整个应用 | 是(写入磁盘) | 用户设置、登录状态 |
二、AppStorage 的基本操作
2.1 写入数据(在 EntryAbility 里)
// AppStorage.setOrCreate(key, defaultValue)// 如果 key 不存在,创建并设置值// 如果 key 已存在,更新值AppStorage.setOrCreate('bottomRectHeight',bottomRectHeight);AppStorage.setOrCreate('topRectHeight',topRectHeight);也可以用set(只更新,key 必须已存在):
AppStorage.set('bottomRectHeight',100);或者get读取:
letheight:number|undefined=AppStorage.get<number>('bottomRectHeight');2.2 在组件中读取:@StorageProp
// GasStationPage.ets@Componentstruct GasStationPage{// 从 AppStorage 读取 'bottomRectHeight' 的值// 如果 AppStorage 里的值变了,这里也会自动更新@StorageProp('bottomRectHeight')bottomRectHeight:number=0;// 0 是默认值(AppStorage里还没有值时使用)@StorageProp('topRectHeight')topRectHeight:number=0;}@StorageProp是单向同步:AppStorage 变化 → 组件属性更新 → UI 刷新。但组件内部修改bottomRectHeight不会反向写回 AppStorage。
2.3 双向同步:@StorageLink
如果需要双向同步(组件修改也写回 AppStorage),用@StorageLink:
@Componentstruct SomeComponent{@StorageLink('userTheme')currentTheme:string='light';// 修改这个会同步到 AppStorage}项目里用@StorageProp而不是@StorageLink:因为安全区域高度只由系统决定,不应该被组件随意修改,单向读取更安全。
三、为什么用 AppStorage 而不是普通全局变量?
你可能会想:直接定义一个全局变量不香吗?
// 直接定义全局变量(不推荐)letglobalTopHeight:number=0;letglobalBottomHeight:number=0;全局变量的问题:
- 改了变量,UI 不刷新——普通变量不是响应式的,改值后还需要手动触发 UI 更新
- 线程安全问题——多个地方同时修改可能出问题
- 没有类型保护——容易写错 key,或者类型不对
AppStorage的优势:
- 响应式——值变化时,
@StorageProp/@StorageLink修饰的属性自动更新,UI 自动重渲 - 类型安全——有泛型支持,
AppStorage.get<number>('key') - 统一管理——所有全局状态都在一个地方
四、数据流向图
EntryAbility │ ├─ 读取状态栏高度 ├─ AppStorage.setOrCreate('topRectHeight', value) └─ AppStorage.setOrCreate('bottomRectHeight', value) │ │ (AppStorage 作为中间层) │ ├─── MainPage │ @StorageProp('topRectHeight') topRectHeight: number = 0 │ @StorageProp('bottomRectHeight') bottomRectHeight: number = 0 │ └─── GasStationPage @StorageProp('topRectHeight') topRectHeight: number = 0 @StorageProp('bottomRectHeight') bottomRectHeight: number = 0当系统安全区域变化时(avoidAreaChange事件),EntryAbility更新AppStorage,所有用@StorageProp绑定了这个 key 的组件都会收到通知,自动刷新 UI。整个流程不需要手动传参。
五、完整使用示例
假设你要在应用里共享用户选择的主题色:
// 1. 在 EntryAbility.onCreate() 里初始化onCreate(want:Want,launchParam:AbilityConstant.LaunchParam):void{AppStorage.setOrCreate('primaryColor','#007AFF');// 初始化主题色}// 2. 在页面A里读取并显示@Componentstruct PageA{@StorageProp('primaryColor')primaryColor:string='#007AFF';build(){Button('确认').backgroundColor(this.primaryColor)// 使用主题色}}// 3. 在设置页里修改(双向同步)@Componentstruct SettingsPage{@StorageLink('primaryColor')// 用 @StorageLink 才能写回primaryColor:string='#007AFF';build(){Button('切换蓝色').onClick(()=>{this.primaryColor='#007AFF';// 修改后自动同步到 AppStorage})Button('切换红色').onClick(()=>{this.primaryColor='#FF3B30';// PageA 的颜色也会自动更新})}}六、AppStorage 的注意事项
6.1 Key 命名要规范
AppStorage 是全局的,如果不同模块用了同名的 key,会互相覆盖:
// 不好的做法——容易冲突AppStorage.setOrCreate('height',100);// 推荐——带模块前缀AppStorage.setOrCreate('window_topRectHeight',100);AppStorage.setOrCreate('window_bottomRectHeight',60);6.2 值类型要一致
// 设置时是 numberAppStorage.setOrCreate('topRectHeight',100);// 读取时类型要匹配@StorageProp('topRectHeight')topRectHeight:number=0;// ✅ 正确// 如果类型不匹配,行为未定义@StorageProp('topRectHeight')topRectHeight:string='0';// ⚠️ 危险6.3 App 重启后数据丢失
AppStorage的数据在内存里,App 关闭后会消失。这也是为什么每次启动都要重新获取安全区域高度。如果需要持久化,改用PersistentStorage:
// 持久化到磁盘(App重启后依然有值)PersistentStorage.persistProp('userSettings',{});七、@State vs @StorageProp 怎么选?
| 场景 | 用什么 |
|---|---|
| 只在当前组件用的数据 | @State |
| 需要在多个页面/组件共享的数据 | AppStorage+@StorageProp |
| 父子组件传数据(只读) | @Prop |
| 父子组件传数据(双向改) | @Link |
| 需要持久化的数据 | PersistentStorage+@StorageProp |
总结
AppStorage是 HarmonyOS 的"全局响应式仓库":
- 写入:
AppStorage.setOrCreate(key, value)(推荐)或AppStorage.set(key, value) - 读取:
@StorageProp('key')单向同步,@StorageLink('key')双向同步 - 特点:响应式,值变化自动触发 UI 刷新,无需手动传参
- 局限:App 关闭后数据消失,持久化需用
PersistentStorage
下一篇讲Navigation 路由系统——从主页到地图页的页面跳转是怎么实现的。