鸿蒙 ArkUI V2 装饰器:AppStorageV2,应用级状态存取,告别 V1 的「set/get 手动同步」

写在前面

如果你写过鸿蒙 ArkUI 应用,大概率遇到过这个场景:

你写了个主题切换功能,V1 用 AppStorage.set('theme', 'dark') 存应用级状态------结果改了之后 UI 不更新,得手动 this.theme = AppStorage.get('theme') 同步。 你查文档发现 V1 的 @StorageLink / @StorageProp 能自动同步------但只能用在 @Component 里,V2 组件用不了。 你查文档发现鸿蒙 6.1 给了 V2 的 AppStorageV2------但点进去发现它没有 set/get,只有 connect 拿可观察对象。API 一脸懵。

这是 V1「set/get 手动同步」和 V2「connect 拿可观察对象」的分水岭。鸿蒙 6.1 给的答案是 AppStorageV2 ------connect(class, key, default) 拿应用级可观察对象,改成员就真触发 UI 重绘,不用手动同步。

本文就用一个真机可跑 的「应用级主题/语言切换」demo,把 AppStorageV2 从「听名字一脸懵」讲到「下个项目直接抄」。代码托管在 AtomGit,文末有链接,真机实拍截图作证。这是 V2 装饰器系列第二篇,接续上篇 @ObservedV2 + @Trace。

适合人群:写过鸿蒙应用、被 V1 AppStorage 手动同步折磨过的同学。 不适合人群:还在学 @State 的同学------出门左转看我的入门篇。


一、先讲清楚:AppStorageV2 到底是啥

一句话:AppStorageV2 是鸿蒙 6.1 V2 应用级状态,用 connect 拿可观察对象,改成员就真重绘。

V1 的 AppStorage.set/get 是键值对存取------改了不自动同步 UI,要手动 @StorageLinkthis.x = AppStorage.get()。V2 的 AppStorageV2.connect 直接拿可观察对象(@ObservedV2 + @Trace 装的 class),改成员就真触发 UI 重绘,不用手动同步。

核心 API 一览:

API 作用 一句话理解
AppStorageV2.connect(type, key, default) 拿应用级可观察对象 「有就拿,没有就用 default 新建」
AppStorageV2.remove(key) 删应用级键 「清理应用级状态」
AppStorageV2.keys() 看所有应用级键 「列出当前存了哪些」

注意:V2 没有 set/get------这是跟 V1 最大的区别,新手最容易踩的坑。


二、动手:一个应用级主题/语言切换的 demo

2.1 定义 @ObservedV2 class + import

typescript 复制代码
import { AppStorageV2 } from '@ohos.arkui.StateManagement'

@ObservedV2
class AppConfig {
  @Trace theme: string = 'light'
  @Trace lang: string = 'zh'
}

三个细节:

  1. import { AppStorageV2 } from '@ohos.arkui.StateManagement'------V2 应用级状态需显式 import,不是全局名
  2. @ObservedV2 class AppConfig------应用级状态必须用 @ObservedV2 class,成员装 @Trace
  3. @Trace theme / @Trace lang------追踪这两个成员变化,改了就触发 UI 重绘

2.2 connect 拿应用级可观察对象

typescript 复制代码
@Entry
@ComponentV2
struct Index {
  // connect 拿应用级可观察对象,key='appConfig',默认 new AppConfig()
  appCfg: AppConfig = AppStorageV2.connect(AppConfig, 'appConfig', () => new AppConfig()) ?? new AppConfig()
  @Local logText: string = '(未操作)'
  @Local opCount: number = 0

  build() {
    // ...
  }
}

connect 三个关键点:

connect(type, key, default) 三参

typescript 复制代码
AppStorageV2.connect(
  AppConfig,           // type: class 类型
  'appConfig',        // key: 应用级键名
  () => new AppConfig()  // defaultCreator: 默认值工厂
)
  • type:class 类型,告诉 AppStorageV2 存什么
  • key:应用级键名,跨组件用同一个 key 拿同一个对象
  • defaultCreator:第一次 connect 时用这个工厂新建默认值

connect 返回 T | undefined

typescript 复制代码
this.appCfg = AppStorageV2.connect(AppConfig, 'appConfig', () => new AppConfig()) ?? new AppConfig()

connect 可能返回 undefined(极端情况),用 ?? new AppConfig() 兜底。

③ 跨组件用同一个 key 拿同一个对象

typescript 复制代码
// 组件 A
appCfg = AppStorageV2.connect(AppConfig, 'appConfig', () => new AppConfig())
// 组件 B
appCfg = AppStorageV2.connect(AppConfig, 'appConfig', () => new AppConfig())
// ← A 和 B 拿到的是同一个对象,A 改 B 自动同步

这是 AppStorageV2 最核心的能力------跨组件共享同一个可观察对象,A 改成员 B 自动重绘。

2.3 改成员 → UI 真重绘

typescript 复制代码
Button('改 theme = dark(@Trace 触发重绘)')
  .width('92%').height(44).fontSize(14)
  .onClick(() => {
    this.appCfg.theme = 'dark'  // ← 改成员,UI 重绘
    this.opCount++
    this.logText = `第 ${this.opCount} 次:theme=dark,UI 重绘`
  })

这是 V2 最核心的能力 ------改 this.appCfg.theme(应用级可观察对象成员)就真触发 UI 重绘。不用像 V1 那样 AppStorage.set + 手动同步。

2.4 remove / keys 管理应用级状态

typescript 复制代码
Button('remove appConfig(AppStorageV2.remove)')
  .onClick(() => {
    AppStorageV2.remove('appConfig')  // ← 删应用级键
  })

Button('keys() 看所有应用级键')
  .onClick(() => {
    this.logText = `keys=${JSON.stringify(AppStorageV2.keys())}`  // ← 列所有键
  })

remove 删应用级键,keys 列所有应用级键------管理用。


三、真机实拍:改成员真触发 UI 重绘

我把这个 demo 装到真机上跑(鸿蒙 6.1.1.125, API 24),依次点改 theme=dark + 改 lang=en,下面两张都是真机实拍,没有任何 P 图。

初始态:应用级状态(theme=light, lang=zh, opCount=0)+ 5 个按钮:

点改 theme=dark + 改 lang=en 后:theme=dark, lang=en, opCount=2, 日志「第 2 次:lang=en,UI 重绘」:

重点看第二张:theme 从 light 变成 dark、lang 从 zh 变成 en、opCount 从 0 变成 2------改应用级可观察对象成员就真触发了 UI 重绘,不用手动同步 。这是 AppStorageV2.connect + @ObservedV2 + @Trace 的真机证明。


四、V2 AppStorageV2 vs V1 AppStorage:啥差异

新手最容易纠结的问题:既然 V1 AppStorage 那么标准,鸿蒙为啥要造 V2?

维度 V1 AppStorage V2 AppStorageV2
import 全局名 import { AppStorageV2 } from '@ohos.arkui.StateManagement'
存取 API set/get 键值对 connect 拿可观察对象
改成员触发重绘 不触发(要手动同步) 触发(@Trace 装的成员)
跨组件同步 @StorageLink / @StorageProp 同 key connect 同对象
配套装饰 @Component + @State @ComponentV2 + @Local
类型安全 弱(any) 强(class 类型)

一句话决策:新项目鸿蒙 6.1+ 用 V2,改成员就重绘不用手动同步;V1 项目维护老代码不动


五、常见坑(都是血泪)

症状 解法
AppStorageV2.set/get 编译报「没有 set 方法」 V2 没有 set/get,用 connect 拿可观察对象
忘 import AppStorageV2 编译报「Cannot find name AppStorageV2」 import { AppStorageV2 } from '@ohos.arkui.StateManagement'
connect 忘装 @ObservedV2 class 改成员不触发重绘 class 必须 @ObservedV2 + 成员 @Trace
connect 返回 undefined 没兜底 运行时 null 引用 ?? new AppConfig() 兜底
跨组件 key 不一致 A 改 B 不同步 跨组件用同一个 key
用在 V1 @Component 编译报「V2 装饰器只能装在 @ComponentV2」 struct 改 @ComponentV2
remove 清理 应用级状态泄漏 不用了调 AppStorageV2.remove(key)

六、PersistenceV2:持久化版应用级状态

鸿蒙 6.1 还给了 PersistenceV2------AppStorageV2 的持久化版,应用重启后状态还在:

typescript 复制代码
import { PersistenceV2 } from '@ohos.arkui.StateManagement'
// PersistenceV2.globalConnect(...) 持久化版 connect
// PersistenceV2.save(key) 主动保存到磁盘
API 用途 与 AppStorageV2 的区别
AppStorageV2.connect 应用生命周期内共享 重启后丢
PersistenceV2.globalConnect 持久化到磁盘 重启后还在
PersistenceV2.save 主动保存 写磁盘

场景决策 :主题/语言这种用户设置用 PersistenceV2(重启还在),临时状态用 AppStorageV2(重启丢)。


七、完整代码仓库

本文所有代码都已托管到 AtomGit,欢迎 clone、提 issue、点 star:

🔗 仓库地址atomgit.com/JaneConan/a...

仓库包含:

  • 完整的「AppStorageV2 应用级主题/语言切换」demo 工程
  • Index.ets 主页面(import AppStorageV2 + @ObservedV2 class + connect + 改成员重绘 + remove/keys
  • 跨组件共享同 key 的姿势说明
  • 可直接用 DevEco Studio 打开运行(真机装普通应用必能跑)

八、下一步该学什么?

跑通这个 demo 之后,你的 V2 应用级状态就入门了。这是 V2 装饰器系列第二篇,后续按这个顺序往下:

  1. @Param + @Once (下一篇):V2 父子传参,替代 V1 @Prop + @Link
  2. @Provider + @Consumer :V2 跨层传递,替代 V1 @Provide + @Consume
  3. @Monitor :V2 监听变化,替代 V1 @Watch
  4. @Computed:V2 计算属性,自动派生
  5. PersistenceV2:持久化版应用级状态,重启还在

写在最后

AppStorageV2 的本质,是**「鸿蒙 6.1 给应用级状态 connect 拿可观察对象的原生机制」**------不是 V1 的「set/get 键值对」,是 V2 专门给精细追踪的原生机制。代价是 import 多一行、connect 三参多一步。

一旦你开始用 V2 思维写应用级状态,你会发现大部分「主题切换」「语言切换」「用户信息共享」「全局计数器」的需求,都是 AppStorageV2.connect + @ObservedV2 + @Trace 的自然结果。代码量比 V1 手动同步少一半,精细度高一倍。

代码已经给你了,仓库链接在上面。现在关掉这篇文章,打开 DevEco Studio,把 demo 跑起来,亲手点改 theme 改 lang 感受下应用级状态自动同步。

跑通了,回来评论区打个「1」,我看看有多少人真的动手了。🚀


作者:JaneConan 仓库:atomgit.com/JaneConan/a... 协议:Apache-2.0,随便用,别告我

相关推荐
咕白m6251 小时前
通过 C++ 写入数据到 Excel 文档
c++·后端
极光技术熊1 小时前
AI应用开发中的流式输出:从协议原理到工程实战的完整指南
后端·架构
xn71331 小时前
AI SDK 7 迁移实战:TypeScript 通过后,生产环境还会坏在哪里?
vue.js·人工智能·后端
Lcos1 小时前
我顺手跑了个 go test,结果跑出了 panic
后端
程序员David1 小时前
雪花 ID + MyBatis = 隐式转 Double 撞键?我排查了一整天的隐蔽坑
后端
星栈独行1 小时前
Node 接口该写同步还是异步?
服务器·开发语言·后端·程序人生·node.js
云边有个稻草人1 小时前
传统数据库迁移国产化,别把 WHERE 条件当成程序执行
后端
小陈工1 小时前
第8篇:Flask轻量级框架与扩展生态深度解析(下)
后端·python·面试
Conan在掘金1 小时前
鸿蒙 韶非 UI 系列:能力调用 startAbilityForResult,跳能力拿回参,鸿蒙能力路由入门
后端