当前位置: 首页 > news >正文

鸿蒙应用状态管理新方案:AppStorageV2与PersistenceV2深度详解

在鸿蒙应用开发中,状态管理一直是构建复杂应用的核心挑战。从API 12开始,鸿蒙推出了全新的V2版本状态管理方案,其中AppStorageV2和PersistenceV2作为核心组件,为开发者提供了更强大、更灵活的状态管理能力。本文将深入剖析这两个组件的工作原理、使用方法和最佳实践。

文章目录

    • 一、AppStorageV2:应用级全局UI状态存储
      • 1.1 基本概念与特点
      • 1.2 核心API详解
        • connect方法:创建或获取数据
        • remove方法:删除数据
        • keys方法:获取所有存储的键
      • 1.3 使用限制
      • 1.4 与装饰器的配合使用
        • @ObservedV2装饰类
        • @Trace装饰属性
      • 1.5 实际应用场景
        • 跨页面数据共享
    • 二、PersistenceV2:持久化存储UI状态
      • 2.1 基本概念与特点
      • 2.2 核心API详解
        • connect方法:创建或获取数据
        • save方法:手动持久化数据
        • notifyOnError方法:响应序列化或反序列化失败的回调
        • globalConnect方法(API 18+)
      • 2.3 持久化规则与限制
        • 自动持久化规则
        • 支持的持久化类型
        • 不支持的持久化类型
        • 使用限制
      • 2.4 实际应用场景
        • 用户偏好设置持久化
        • 登录状态持久化
    • 三、AppStorageV2与PersistenceV2的配合使用
      • 3.1 数据流关系
      • 3.2 典型应用模式
      • 3.3 多设备同步配置
    • 四、从V1到V2的迁移指南
      • 4.1 核心装饰器对应关系
      • 4.2 迁移示例
    • 五、最佳实践与注意事项
      • 5.1 最佳实践
      • 5.2 注意事项
    • 六、总结
    • 其他资源

一、AppStorageV2:应用级全局UI状态存储

1.1 基本概念与特点

AppStorageV2是在应用UI启动时会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。AppStorageV2将在应用运行过程保留其数据。数据通过唯一的键字符串值访问。

AppStorageV2具有以下核心特点:

  • 单例模式:应用启动时自动创建,整个应用中唯一实例,确保数据一致性
  • 全局可访问:在任何页面、任何UIAbility中都可访问
  • 跨UIAbility共享:支持主线程内多个UIAbility实例间的数据共享
  • 内存存储:数据在应用运行期间保留,应用关闭后数据丢失
  • 数据隔离:与V1版本的AppStorage数据互不共享
  • UI同步:可以和UI组件同步,且可以在应用业务逻辑中被访问

1.2 核心API详解

connect方法:创建或获取数据
static connect<T extends object>(type: TypeConstructorWithArgs<T>,keyOrDefaultCreator?: string | StorageDefaultCreator<T>,defaultCreator?: StorageDefaultCreator<T>
): T | undefined;

参数说明:

  • type:指定的类型,若未指定key,则使用type的name作为key
  • keyOrDefaultCreator:指定的key,或者是默认数据的构造器
  • defaultCreator:默认数据的构造器

返回值: 成功返回指定类型的数据对象,失败返回undefined

说明:

  1. 若未指定key,使用第二个参数作为默认构造器;否则使用第三个参数作为默认构造器(第二个参数非法也使用第三个参数作为默认构造器)
  2. 确保数据已经存储在AppStorageV2中,可省略默认构造器,获取存储的数据;否则必须指定默认构造器,不指定将导致应用异常
  3. 同一个key,connect不同类型的数据会导致应用异常,应用需要确保类型匹配
  4. key建议使用有意义的值,可由字母、数字、下划线组成,长度不超过255,使用非法字符或空字符的行为是未定义的
  5. 关联@Observed对象时,由于该类型的name属性未定义,需要指定key或者自定义name属性

使用示例:

@ObservedV2
class UserInfo {@Trace name: string = "默认名称"age: number = 18
}// 方式1:不指定key,使用类型名作为key
let user1 = AppStorageV2.connect(UserInfo, () => new UserInfo())// 方式2:指定key和默认构造器
let user2 = AppStorageV2.connect(UserInfo, "user_key", () => new UserInfo())// 方式3:获取已存在的数据(确保数据已存在)
let existingUser = AppStorageV2.connect(UserInfo, "user_key")
remove方法:删除数据
static remove<T>(keyOrType: string | TypeConstructorWithArgs<T>): void;

参数说明:

  • keyOrType:需要删除的key;如果指定的是type类型,删除的key为type的name

返回值:

说明: 删除AppStorageV2中不存在的key会报警告

使用示例:

// 通过key删除
AppStorageV2.remove("user_key")// 通过类型删除
AppStorageV2.remove(UserInfo)
keys方法:获取所有存储的键
static keys(): Array<string>;

参数:

返回值: 所有AppStorageV2中的key

使用示例:

let allKeys = AppStorageV2.keys()
console.log("存储的键列表:" + allKeys.join(","))

1.3 使用限制

  1. 仅UI线程可用:需要配合UI使用(UI线程),不能在其他线程使用,如不支持@Sendable
  2. 不支持的特殊类型:不支持collections.Set、collections.Map等集合类型
  3. 非内置类型限制:不支持非buildin类型,如PixelMap、NativePointer、ArrayList等Native类型
  4. 类型一致性:同一个key的前后connect操作必须使用相同的类型

注意:AppStorageV2从API version 12开始支持

1.4 与装饰器的配合使用

@ObservedV2装饰类

用于标记可被观察的类,使其实例可以被多个UI组件共享和观察。

@ObservedV2
class Config {@Trace theme: string = "light";fontSize: number = 16;
}
@Trace装饰属性

用于标记需要触发UI刷新的属性。只有被@Trace装饰的属性发生变化时,才会自动触发UI组件的刷新。

@ObservedV2
class UserData {@Trace name: string = "默认用户"; // 修改时会触发UI刷新level: number = 1; // 修改时不会自动触发UI刷新
}

1.5 实际应用场景

跨页面数据共享

以下是两个页面通过AppStorageV2共享数据的完整示例:

1. 定义共享数据类型

// Sample.ets
@ObservedV2
export class Sample {@Trace p1: number = 0;p2: number = 10;
}

2. 第一个页面(Page1)

// Page1.ets
import { AppStorageV2 } from '@kit.ArkUI';
import { Sample } from '../Sample';@Entry
@ComponentV2
struct Page1 {@Local prop: Sample = AppStorageV2.connect(Sample, () => new Sample())!;pageStack: NavPathStack = new NavPathStack();build() {Navigation(this.pageStack) {Column({ space: 15 }) {Button('跳转到Page2').onClick(() => {this.pageStack.pushPathByName('Page2', null);})Text(`Page1中p1的值:${this.prop.p1}(点击+1)`).onClick(() => {this.prop.p1++; // p1有@Trace,修改后UI会刷新})Text(`Page1中p2的值:${this.prop.p2}(点击+1)`).onClick(() => {this.prop.p2++; // p2没有@Trace,修改后UI不会自动刷新})Text(`当前存储的key:${AppStorageV2.keys().join(',')}`)}}}
}

3. 第二个页面(Page2)

// Page2.ets
import { AppStorageV2 } from '@kit.ArkUI';
import { Sample } from '../Sample';@Builder
export function Page2Builder() {Page2()
}@ComponentV2
struct Page2 {@Local prop: Sample = AppStorageV2.connect(Sample, () => new Sample())!;pathStack: NavPathStack = new NavPathStack();build() {NavDestination() {Column({ space: 15 }) {Text(`Page2中p1的值:${this.prop.p1}(点击+1)`).onClick(() => {this.prop.p1++; // p1修改后UI会刷新})Text(`Page2中p2的值:${this.prop.p2}(点击+1)`).onClick(() => {this.prop.p2++; // p2修改后UI不自动刷新})}}.onReady((context: NavDestinationContext) => {this.pathStack = context.pathStack;})}
}

二、PersistenceV2:持久化存储UI状态

2.1 基本概念与特点

PersistenceV2是在应用UI启动时会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。数据通过唯一的键字符串值访问。不同于AppStorageV2,PersistenceV2还将最新数据储存在设备磁盘上(持久化)。这意味着,应用退出再次启动后,依然能保存选定的结果。

对于与PersistenceV2关联的@ObservedV2对象,该对象的@Trace属性的变化,会触发整个关联对象的自动持久化;非@Trace属性的变化则不会,如有必要,可调用PersistenceV2 API手动持久化。

PersistenceV2具有以下核心特点:

  • 数据持久化:数据保存到设备磁盘,应用重启后数据依然保留
  • 自动同步:被@Trace装饰的属性变化时,自动触发数据持久化
  • 手动持久化:支持通过API手动触发非@Trace属性的数据持久化
  • 错误回调:提供错误通知机制,处理序列化或反序列化失败情况
  • UI同步:可以和UI组件同步,且可以在应用业务逻辑中被访问
  • 跨UIAbility共享:支持应用的主线程内多个UIAbility实例间的状态共享

注意:PersistenceV2从API version 12开始支持

2.2 核心API详解

connect方法:创建或获取数据
static connect<T extends object>(type: TypeConstructorWithArgs<T>,keyOrDefaultCreator?: string | StorageDefaultCreator<T>,defaultCreator?: StorageDefaultCreator<T>,options?: { distributed?: boolean }
): T | undefined;

参数说明:

  • type:指定的类型,若未指定key,则使用type的name作为key
  • keyOrDefaultCreator:指定的key,或者是默认数据的构造器
  • defaultCreator:默认数据的构造器
  • options:可选,支持distributed: boolean配置,启用多设备数据同步

返回值: 成功返回指定类型的数据对象,失败返回undefined

说明:

  1. 若未指定key,使用第二个参数作为默认构造器;否则使用第三个参数作为默认构造器(第二个参数非法也使用第三个参数作为默认构造器)
  2. 确保数据已经存储在PersistenceV2中,可省略默认构造器,获取存储的数据;否则必须指定默认构造器,不指定将导致应用异常
  3. 同一个key,connect不同类型的数据会导致应用异常,应用需要确保类型匹配
  4. key建议使用有意义的值,可由字母、数字、下划线组成,长度不超过255,使用非法字符或空字符的行为是未定义的
  5. 关联@Observed对象时,由于该类型的name属性未定义,需要指定key或者自定义name属性

使用示例:

@ObservedV2
class UserSettings {@Trace theme: string = "light";fontSize: number = 16;
}// 基本使用
let settings = PersistenceV2.connect(UserSettings, "user_settings", () => new UserSettings())// 启用分布式(多设备同步)
let distributedSettings = PersistenceV2.connect(UserSettings, "settings", () => new UserSettings(), { distributed: true }
)
save方法:手动持久化数据
static save<T>(keyOrType: string | TypeConstructorWithArgs<T>): void;

参数说明:

  • keyOrType:需要手动持久化的key;如果指定的是type类型,key为type的name

返回值:

说明:

  • 由于非@Trace的数据改变不会触发PersistenceV2的自动持久化,如有必要,可调用该接口持久化对应key的数据
  • 手动持久化当前内存中不处于connect状态的key是无意义的
notifyOnError方法:响应序列化或反序列化失败的回调
static notifyOnError(callback: PersistenceErrorCallback | undefined): void;

参数说明:

  • callback:当序列化或者反序列化失败时,执行该回调;若传入undefined,取消该回调

返回值:

说明:

  • 将数据存入磁盘时,需要对数据进行序列化;当某个key序列化失败时,错误是不可预知的;可调用该接口捕获异常

使用示例:

PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {console.error(`持久化错误 - key: ${key}, reason: ${reason}, message: ${msg}`);
});
globalConnect方法(API 18+)
static globalConnect<T extends object>(type: TypeConstructorWithArgs<T>,keyOrDefaultCreator?: string | StorageDefaultCreator<T>,defaultCreator?: StorageDefaultCreator<T>
): T | undefined;

功能: 创建或获取应用级别的持久化数据,跨模块共享

与connect的区别:

  • connect:模块级别存储,不同模块使用相同key会创建独立副本
  • globalConnect:应用级别存储,跨模块共享同一份数据

2.3 持久化规则与限制

自动持久化规则
  • @Trace属性:修改时自动触发持久化
  • 非@Trace属性:修改后不会自动持久化,需要手动调用save()
支持的持久化类型
  • 基本类型:string、number、boolean、enum等
  • 复合类型:通过@Type装饰的嵌套对象
  • 数组类型:通过@Type装饰的数组
不支持的持久化类型
  • Map/Set:不支持直接持久化,需要转换为数组
  • 循环引用:不支持包含循环引用的对象
  • 非JSON兼容类型:如Date、Symbol、undefined等
  • any类型:禁止使用,无法保证序列化安全
使用限制
  1. 仅UI线程可用:需要配合UI使用(UI线程),不能在其他线程使用,如不支持@Sendable
  2. 特殊类型限制:不支持collections.Set、collections.Map等集合类型
  3. 非内置类型限制:不支持非buildin类型,如PixelMap、NativePointer、ArrayList等Native类型
  4. 数据大小限制:单个key支持数据大小约8k,过大会导致持久化失败
  5. 对象类型限制:持久化的数据必须是class对象,不能是容器(如Array、Set、Map),不能是buildin的构造对象(如Date、Number)
  6. 循环引用限制:不支持循环引用的对象
  7. 自动持久化触发条件:只有@Trace的数据改变会触发自动持久化,如V1状态变量、@Observed对象、普通数据的改变不会触发持久化
  8. 性能考虑:不宜大量持久化数据,可能会导致页面卡顿

2.4 实际应用场景

用户偏好设置持久化
@ObservedV2
class ThemeConfig {@Trace primaryColor: string = '#FF6200';@Trace isDarkMode: boolean = false;
}// 持久化存储主题配置
const theme = PersistenceV2.connect(ThemeConfig, 'userTheme', () => new ThemeConfig()
);// 在组件中使用
@ComponentV2
struct SettingsPage {@Consumer theme: ThemeConfig;build() {Column() {Text('主题颜色: ' + this.theme.primaryColor)Toggle({ isOn: this.theme.isDarkMode }).onChange((value) => {this.theme.isDarkMode = value; // 自动持久化})}}
}
登录状态持久化
@ObservedV2
class UserSession {@Trace isLoggedIn: boolean = false;@Trace userId: string = '';
}// 持久化存储登录状态
const session = PersistenceV2.connect(UserSession, 'loginSession', () => new UserSession()
);// 登录处理
function handleLogin(userId: string) {session.isLoggedIn = true;session.userId = userId; // 自动持久化
}// 登出处理
function handleLogout() {session.isLoggedIn = false;session.userId = ''; // 自动持久化
}

三、AppStorageV2与PersistenceV2的配合使用

3.1 数据流关系

UI组件 <--> AppStorageV2(内存) <--> PersistenceV2(磁盘)

3.2 典型应用模式

在实际应用中,我们通常会结合使用这两个组件来实现完整的状态管理方案:

@Entry
@ComponentV2
struct TodoList {// 临时设置(使用AppStorageV2)@Local setting: Setting = AppStorageV2.connect(Setting, 'Setting', () => new Setting())!;// 持久化任务列表(使用PersistenceV2)@Local taskList: TaskList = PersistenceV2.connect(TaskList, 'TaskList', () => new TaskList([]))!;build() {Column() {// 显示/隐藏已完成任务开关Toggle({type: ToggleType.Switch, isOn: this.setting.showCompletedTask}).onChange((isOn) => {this.setting.showCompletedTask = isOn;})// 任务列表ForEach(this.taskList.tasks, (task: Task) => {if (this.setting.showCompletedTask || !task.isFinish) {TaskItem({ task: task })}})}}
}

3.3 多设备同步配置

对于需要在多设备间同步的数据,可以启用分布式功能:

// 启用多设备同步的数据
const sharedData = AppStorageV2.connect(SharedClass, 'sharedKey', () => new SharedClass(), { distributed: true } // 关键配置
);

四、从V1到V2的迁移指南

4.1 核心装饰器对应关系

V1装饰器V2装饰器说明
@State@Local功能类似,@Local禁止外部初始化
@Provide/@Consume@Provider/@Consumer基本兼容,alias规则有变化
@LocalStorage全局@ObservedV2/@Trace使用类替代LocalStorage实例
PersistentStoragePersistenceV2功能更强大,可独立使用

4.2 迁移示例

V1版本代码:

@Entry
@Component
struct Parent {@State parentFruit: Fruit = new Fruit();build() {Child({ fruit: this.parentFruit })}
}

V2迁移后代码:

@ObservedV2
class Fruit {@Trace apple: number = 5;@Trace orange: number = 10;clone(): Fruit {let newFruit = new Fruit();newFruit.apple = this.apple;newFruit.orange = this.orange;return newFruit;}
}@Entry
@ComponentV2
struct Parent {@Local fruit: Fruit = new Fruit();build() {Child({ fruit: this.fruit.clone() })}
}

五、最佳实践与注意事项

5.1 最佳实践

  1. 合理设计数据结构:避免持久化大型数据集或频繁变化的变量
  2. 最小化共享范围:根据需求选择最小范围的共享方案
  3. 类型安全:确保存储的数据类型与使用时一致
  4. 错误处理:实现PersistenceV2的错误回调以处理持久化失败情况
  5. 性能优化:对频繁修改但不需要UI刷新的属性,避免使用@Trace装饰

5.2 注意事项

  1. 线程安全:AppStorageV2和PersistenceV2只能在UI线程中使用
  2. 数据大小:避免存储过大的数据,会影响性能
  3. 敏感信息:不要直接存储敏感信息(如密码、Token),建议加密存储
  4. 内存管理:及时清理不需要的临时数据,避免内存占用过高
  5. 错误恢复:实现适当的错误恢复机制,防止应用崩溃

六、总结

AppStorageV2和PersistenceV2作为鸿蒙API 12推出的新一代状态管理方案,通过提供更精细的状态控制、更灵活的持久化机制和更强大的跨组件数据共享能力,极大地简化了鸿蒙应用的状态管理复杂性。

通过合理运用这些组件,开发者可以构建出状态管理清晰、性能优化良好、用户体验流畅的鸿蒙应用。随着鸿蒙生态的不断发展,这些状态管理工具也将持续完善,为开发者提供更强大的支持。

其他资源

官方文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V14/arkts-new-appstoragev2-V14

http://www.dtcms.com/a/578520.html

相关文章:

  • 状态管理(State Management)
  • 网站源码设计工程信息
  • 怎么搭建一个视频网站室内设计在线网站
  • 广州注册公司最新流程石家庄视频优化公司
  • DIC技术在汽车风洞试验中的革新应用:流场与形变的全场测量
  • Linux 的 RDP 代理
  • 怎么用手机做网站服务器win2008 iis 新建网站
  • Windows10 离线安装.NET3.5
  • Keepalived核心机制与生产实战全解析
  • 夺宝网站制作网站建设公开
  • php网站建设课程作业关键词优化公司网站
  • C++中的多态:动态多态与静态多态详解
  • C++高级数据结构:并查表
  • 牛牛网站开发如何弄一个自己的网站
  • 云计算产品-介绍--计算篇
  • 岳池网站建设珠海seo海网站建设
  • 技术解析:鸿蒙 PC 为什么采用 aarch64 架构?
  • B样条曲线降阶方法介绍
  • SciPy 图结构
  • 深圳本地网站建设做酒业网站的要求
  • Linux下查看指定内容的完整日志
  • 做网站 用什么兼容学院网站设计模板
  • 财务分析怎么做?4大关键模块手把手教你做!
  • 【计算机软件资格考试】软考综合知识题高频考题及答案解析6
  • 电商商城网站建设方案wordpress博客xiu
  • wangEditor在弹窗中的销毁注意事项,报错Error: Cannot resolve a Slate range from DOM rang
  • 防滑齿分布与牙钳防滑效能的关系
  • 商城网站网络公司wordpress主题 报纸
  • 站长工具seo诊断潍坊专业网站建设哪家便宜
  • 嵌入式Linux系统性能优化:深入剖析I/O性能瓶颈