android2harmony 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/agents/self-tester.md +339 -0
  2. package/dist/index.js +625 -7
  3. package/dist/index.js.map +4 -4
  4. package/package.json +37 -29
  5. package/skills/hmos-incremental-ui-align/README.md +251 -0
  6. package/skills/hmos-incremental-ui-align/SKILL.md +365 -0
  7. package/skills/hmos-incremental-ui-align/diff_analysis.md +53 -0
  8. package/skills/hmos-incremental-ui-align/page_align.md +62 -0
  9. package/skills/hmos-incremental-ui-align/references/Comparison_Template.md +38 -0
  10. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md +648 -0
  11. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md +2089 -0
  12. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md +1033 -0
  13. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md +1183 -0
  14. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md +576 -0
  15. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md +297 -0
  16. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md +395 -0
  17. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md +903 -0
  18. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md +106 -0
  19. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md +1178 -0
  20. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/MVVM/346/250/241/345/274/217V1.md +911 -0
  21. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +355 -0
  22. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md +11 -0
  23. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/!!/350/257/255/346/263/225/357/274/232/345/217/214/345/220/221/347/273/221/345/256/232.md +206 -0
  24. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Computed/350/243/205/351/245/260/345/231/250/357/274/232/350/256/241/347/256/227/345/261/236/346/200/247.md +373 -0
  25. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Event/350/243/205/351/245/260/345/231/250/357/274/232/350/247/204/350/214/203/347/273/204/344/273/266/350/276/223/345/207/272.md +158 -0
  26. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Local/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/351/203/250/347/212/266/346/200/201.md +750 -0
  27. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Monitor/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/344/277/256/346/224/271/345/274/202/346/255/245/347/233/221/345/220/254.md +1704 -0
  28. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@ObservedV2/350/243/205/351/245/260/345/231/250/345/222/214@Trace/350/243/205/351/245/260/345/231/250/357/274/232/347/261/273/345/261/236/346/200/247/345/217/230/345/214/226/350/247/202/346/265/213.md +1012 -0
  29. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Once/350/243/205/351/245/260/345/231/250/357/274/232/345/210/235/345/247/213/345/214/226/345/220/214/346/255/245/344/270/200/346/254/241.md +164 -0
  30. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Param/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/244/226/351/203/250/350/276/223/345/205/245.md +840 -0
  31. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Provider/350/243/205/351/245/260/345/231/250/345/222/214@Consumer/350/243/205/351/245/260/345/231/250/357/274/232/350/267/250/347/273/204/344/273/266/345/261/202/347/272/247/345/217/214/345/220/221/345/220/214/346/255/245.md +856 -0
  32. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Type/350/243/205/351/245/260/345/231/250/357/274/232/346/240/207/350/256/260/347/261/273/345/261/236/346/200/247/347/232/204/347/261/273/345/236/213.md +83 -0
  33. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/AppStorageV2/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200UI/347/212/266/346/200/201/345/255/230/345/202/250.md +294 -0
  34. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/MVVM/346/250/241/345/274/217/357/274/210V2/357/274/211.md +1407 -0
  35. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/PersistenceV2/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +1220 -0
  36. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/_/350/214/203/345/274/217/351/200/211/346/213/251/350/257/264/346/230/216.md +47 -0
  37. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2//347/212/266/346/200/201/347/256/241/347/220/206V1/345/220/221V2/350/277/201/347/247/273/344/270/216/346/267/267/347/224/250/346/214/207/345/257/274.md +840 -0
  38. package/skills/hmos-incremental-ui-align/references/State_Model_Template.md +74 -0
  39. package/skills/hmos-incremental-ui-align/references/UI_Analysis_Template.md +34 -0
  40. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +2533 -0
  41. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-interaction-mapping-reference.md +555 -0
  42. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-layout-mapping-reference.md +117 -0
  43. package/skills/hmos-incremental-ui-align/scripts/app_feature_verify.ts +999 -0
  44. package/skills/hmos-incremental-ui-align/scripts/extract_checklist.ts +343 -0
  45. package/skills/hmos-incremental-ui-align/scripts/navigation-capure.md +76 -0
  46. package/skills/hmos-incremental-ui-align/scripts/page_capture.ts +977 -0
  47. package/skills/hmos-incremental-ui-align/scripts/page_capture_burst.ts +188 -0
  48. package/tools/autotest/deps/autotest-agent-0.1.1.tgz +0 -0
  49. package/tools/autotest/engine/batch-launcher.ts +326 -0
  50. package/tools/autotest/engine/report-tool.ts +773 -0
  51. package/tools/autotest/engine/self-test-runner.ts +1024 -0
  52. package/tools/autotest/engine/testcases-tool.ts +246 -0
  53. package/tools/autotest/resolve-metadata-tool.ts +143 -0
  54. package/tools/autotest/runner/logger.ts +45 -0
  55. package/tools/autotest/runner/process-utils.ts +41 -0
  56. package/tools/autotest/validate.ts +115 -0
@@ -0,0 +1,1220 @@
1
+ 为了增强状态管理框架对持久化存储UI的能力,开发者可以使用PersistenceV2存储持久化的数据。
2
+
3
+ PersistenceV2是应用程序中的可选单例对象。此对象的作用是持久化存储UI相关的数据,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同。
4
+
5
+ PersistenceV2提供状态变量持久化能力,开发者可以通过connect或者globalConnect绑定同一个key,在状态变量变化和应用冷启动时,实现持久化能力。
6
+
7
+ 在阅读本文档前,建议提前阅读:[@ComponentV2](../../../../学习UI范式基本语法/自定义组件/创建自定义组件/arkts-create-custom-components.md#componentv2),[@ObservedV2和@Trace](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace),配合阅读:[PersistenceV2-API文档](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/@ohos.arkui.StateManagement (状态管理)/js-apis-statemanagement.md#persistencev2>)。
8
+
9
+ 说明
10
+
11
+ PersistenceV2从API version 12开始支持。
12
+
13
+ globalConnect从API version 18开始支持,行为和connect保持一致,唯一的区别为connect的底层存储路径为module级别的路径,而globalConnect的底层存储路径为应用级别,详细区别见使用场景[在不同的module中使用connect和globalConnect](arkts-new-persistencev2.md#在不同的module中使用connect和globalconnect)。
14
+
15
+ globalConnect从API version 23开始支持[集合类型](arkts-new-persistencev2.md#globalconnect支持集合的类型)(Array、Map、Set、Date、collections.Array、collections.Map、collections.Set)的持久化,支持在UI线程持久化@Sendable类型的数据持久化,支持持久化循环引用的对象,支持持久化单个key超过8k的数据。目前建议开发者使用API version 23的新增的globalConnect接口。
16
+
17
+ ## 概述
18
+
19
+ PersistenceV2是在应用UI启动时会被创建的单例。它的目的是提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。数据通过唯一的键值字符串访问。不同于AppStorageV2,PersistenceV2还将最新数据存储在设备磁盘上(持久化)。这意味着,应用退出再次启动后,依然能保存选定的结果。
20
+
21
+ 对于与PersistenceV2关联的[@ObservedV2](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace)对象,该对象的[@Trace](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace)属性的变化,会触发**整个关联对象的自动持久化**;非[@Trace](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace)属性的变化则不会,如有必要,可调用PersistenceV2 API手动持久化。请注意:被PersistenceV2持久化的类属性必须要有初值,否则不支持持久化。
22
+
23
+ PersistenceV2可以和UI组件同步,且可以在应用业务逻辑中被访问。
24
+
25
+ PersistenceV2支持应用的[主线程](<../../../../../../Ability Kit(程序框架服务)/Stage模型开发指导/线程模型/thread-model-stage.md>)内多个UIAbility实例间的状态共享。
26
+
27
+ PersistenceV2继承自[AppStorageV2](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/@ohos.arkui.StateManagement (状态管理)/js-apis-statemanagement.md#appstoragev2>),支持通过[connect](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/@ohos.arkui.StateManagement (状态管理)/js-apis-statemanagement.md#connect>)创建或获取存储的数据。
28
+
29
+ ## 使用说明
30
+
31
+ * globalConnect:创建或获取存储的数据。
32
+
33
+ 说明
34
+
35
+ 1、关联[@Observed](../../../状态管理(V1)/管理组件拥有的状态/@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化/arkts-observed-and-objectlink.md)对象时,由于该类型的name属性未定义,需要指定key或者自定义name属性。
36
+
37
+ 2、 globalConnect为应用级别存储,对于一个key,整个应用在对应加密分区只有一份存储路径。使用PersistenceV2的connect存储的数据路径为module级别,即哪个module调用了connect,数据副本存入对应module的持久化文件中。如果多个module使用相同的key,则数据为最先使用connect的module,并且PersistenceV2中的数据也会存入最先使用connect的module里。因为存储路径在应用第一个ability启动时就已确定,为该ability所属的module。如果一个ability调用了connect,并且该ability能被不同的module拉起, 那么ability存在多少种启动方式,就会有多少份数据副本,因此,建议开发者使用globalConnect代替connect接口。
38
+ * remove:删除指定key的存储数据。删除PersistenceV2中不存在的key会报警告。
39
+ * keys:返回所有PersistenceV2中的key。包括module级别存储路径和应用级别存储路径中的所有key。
40
+ * save:手动持久化数据。
41
+ * notifyOnError:响应序列化或反序列化失败的回调。将数据存入磁盘时,需要对数据进行序列化;当某个key序列化失败时,错误是不可预知的;可调用该接口捕获异常。
42
+
43
+ 以上接口详细描述请参考[PersistenceV2-API文档](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/@ohos.arkui.StateManagement (状态管理)/js-apis-statemanagement.md#persistencev2>)和[AppStorageV2-API文档](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/@ohos.arkui.StateManagement (状态管理)/js-apis-statemanagement.md#appstoragev2>)。
44
+
45
+ ## 使用限制
46
+
47
+ 1、需要配合UI使用(UI线程),不能在其他线程使用。在API version 23以前,不支持@Sendable。
48
+
49
+ * 从API version 23开始,提供globalConnect接口,支持在UI线程持久化@Sendable装饰的类对象,其成员属性的类型需为基础内置类型(string、number和boolean)。
50
+
51
+ 2、在API version 23以前,不支持collections.Set、collections.Map等类型。
52
+
53
+ * 从API version 23开始,提供globalConnect接口,支持[collections.Set](<../../../../../../../../harmonyos-references/ArkTS(方舟编程语言)/ArkTS API/@arkts.collections (ArkTS容器集)/Class (Set)/arkts-apis-arkts-collections-set.md>)、[collections.Map](<../../../../../../../../harmonyos-references/ArkTS(方舟编程语言)/ArkTS API/@arkts.collections (ArkTS容器集)/Class (Map)/arkts-apis-arkts-collections-map.md>)和[collections.Array](<../../../../../../../../harmonyos-references/ArkTS(方舟编程语言)/ArkTS API/@arkts.collections (ArkTS容器集)/Class (Array)/arkts-apis-arkts-collections-array.md>)。collections.Set、collections.Map和collections.Array本身无法观察,在globalConnect接口使用defaultCreator时,需要使用[UIUtils.makeObserved](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/@ohos.arkui.StateManagement (状态管理)/js-apis-statemanagement.md#makeobserved>),才能在值变化时自动保存,如果不使用,开发者需要手动调用[PersistenceV2.save(key)](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/@ohos.arkui.StateManagement (状态管理)/js-apis-statemanagement.md#save>)保存变化的数据。
54
+
55
+ 如下是新增接口globalConnect支持collections.Array的示例代码:
56
+
57
+ ```
58
+ 1. import { PersistenceV2, UIUtils } from '@kit.ArkUI';
59
+ 2. import { collections } from '@kit.ArkTS';
60
+
61
+ 4. @Entry
62
+ 5. @ComponentV2
63
+ 6. struct Page1 {
64
+ 7. // 支持直接持久化collections.Array的类型
65
+ 8. @Local array: collections.Array<number> = PersistenceV2.globalConnect({
66
+ 9. // 定义持久化的数据类型
67
+ 10. type: collections.Array<number>,
68
+ 11. // 定义默认构造器,返回时需要调用makeObserved,才能实现自动持久化
69
+ 12. defaultCreator: () => UIUtils.makeObserved(new collections.Array<number>(1,2))
70
+ 13. })!;
71
+ 14. // 基于collections.Array构建Repeat的数据源
72
+ 15. toArray<T>(array: collections.Array<T>): Array<T> {
73
+ 16. const result = new Array<T>();
74
+ 17. array.forEach((item: T) => result.push(item));
75
+ 18. return result;
76
+ 19. }
77
+
78
+ 21. build() {
79
+ 22. Column({ space: 10 }) {
80
+ 23. Column({ space: 0 }) {
81
+ 24. Repeat(this.toArray(this.array))
82
+ 25. .each(ri => {
83
+ 26. Row() {
84
+ 27. Text(`Item: `)
85
+ 28. Text(`${ri.item}`)
86
+ 29. }
87
+ 30. })
88
+ 31. .key((item: number, index: number) => `${index} - ${item}`)
89
+ 32. }
90
+ 33. Divider().width('100%')
91
+ 34. // 点击'array.push(0)',重启应用,Repeat数组项是:1, 2, 0
92
+ 35. Button('array.push(0)')
93
+ 36. .onClick(() => {
94
+ 37. this.array.push(Math.round(0));
95
+ 38. })
96
+ 39. .fontSize(24)
97
+ 40. // 点击'array.pop()',重启应用,Repeat数组项是:1, 2
98
+ 41. Button('array.pop()')
99
+ 42. .onClick(() => {
100
+ 43. this.array.pop();
101
+ 44. })
102
+ 45. .fontSize(24)
103
+ 46. // 点击'array.splice(0)',重启应用,Repeat数组项为空
104
+ 47. Button('array.splice(0)')
105
+ 48. .onClick(() => {
106
+ 49. this.array.splice(0);
107
+ 50. })
108
+ 51. .fontSize(24)
109
+ 52. // 点击'splice(1, 0, random)',重启应用:Repeat组件再次显示相同的数组项
110
+ 53. Button('array.splice(1, 0, random)')
111
+ 54. .onClick(() => {
112
+ 55. this.array.splice(1, 0, Math.round(100*Math.random()));
113
+ 56. })
114
+ 57. .fontSize(24)
115
+ 58. // 点击'array.splice(0, 2, random, random)',前两个数组项目被替换,记录下来
116
+ 59. // 重启应用:Repeat组件再次显示数组项
117
+ 60. Button('array.splice(0, 2, random, random)')
118
+ 61. .onClick(() => {
119
+ 62. this.array.splice(2, 2, Math.round(100*Math.random()), Math.round(100*Math.random()));
120
+ 63. })
121
+ 64. .fontSize(24)
122
+ 65. // 点击'array.sort', 对数组项升序排列,重启应用,Repeat组件展示升序数组
123
+ 66. Button('array.sort')
124
+ 67. .onClick(() => {
125
+ 68. this.array.sort((a, b) => a -b);
126
+ 69. })
127
+ 70. .fontSize(24)
128
+ 71. // 点击'array.reverse', 对数组项降序排列,重启应用,Repeat组件展示降序数组
129
+ 72. Button('array.reverse')
130
+ 73. .onClick(() => {
131
+ 74. this.array.reverse();
132
+ 75. })
133
+ 76. .fontSize(24)
134
+ 77. }
135
+ 78. .width('100%')
136
+ 79. }
137
+ 80. }
138
+ ```
139
+
140
+ [TopLevelCollectionsArray.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/PersistenceV2/entry/src/main/ets/pages/TopLevelCollectionsArray.ets#L16-L97)
141
+ * globalConnect在持久化多个相同[集合类型](arkts-new-persistencev2.md#globalconnect支持集合的类型)时,需要提供不同的key来区分持久化数据。
142
+
143
+ 如下展示开发者持久化相同的Array<number>类型的部分示例代码片段:
144
+
145
+ ```
146
+ 1. @Entry
147
+ 2. @ComponentV2
148
+ 3. struct Page1 {
149
+ 4. // 持久化相同容器类型的数据,建议开发者使用不同的key来区分持久化数据
150
+ 5. @Local arr1: Array<number> = PersistenceV2.globalConnect({
151
+ 6. type: Array<number>,
152
+ 7. key: 'arr1',
153
+ 8. defaultCreator: () => UIUtils.makeObserved(new Array<number>()),
154
+ 9. })!;
155
+
156
+ 11. @Local arr2: Array<number> = PersistenceV2.globalConnect({
157
+ 12. type: Array<number>,
158
+ 13. key: 'arr2',
159
+ 14. defaultCreator: () => UIUtils.makeObserved(new Array<number>()),
160
+ 15. })!;
161
+ 16. // ...
162
+ 17. }
163
+ ```
164
+
165
+ 3、不支持非built-in类型,如[PixelMap](<../../../../../../../../harmonyos-references/Image Kit(图片处理服务)/ArkTS API/@ohos.multimedia.image (图片处理)/Interface (PixelMap)/arkts-apis-image-pixelmap.md>)、NativePointer、[ArrayList](<../../../../../../../../harmonyos-references/ArkTS(方舟编程语言)/ArkTS API/@ohos.util.ArrayList (线性容器ArrayList)/js-apis-arraylist.md>)等Native类型。
166
+
167
+ 4、在API version 23以前,单个key支持数据大小约8k,过大会导致持久化失败。
168
+
169
+ * 在API version 23开始,解除单个key只能持久化8K数据的限制,读取和写入持久化存储的数据会在UI线程中同步进行,但开发者需要注意,不建议开发者在UI线程存储大量的持久化数据,会导致界面卡顿。
170
+
171
+ 5、在API version 23以前,持久化的数据必须是class对象,不支持容器类型(如Array、Set、Map),不支持built-in的构造对象(如String、Number),不支持持久化基本类型(如string、number、boolean)。如果需要持久化非class对象,建议使用[Preferences](<../../../../../../ArkData(方舟数据管理)/应用数据持久化/通过用户首选项实现数据持久化 (CC++)/preferences-guidelines.md>)进行数据持久化。
172
+
173
+ * 在API version 23开始,支持持久化Class类型和容器类型(Array、Set、Map,Date)。支持built-in的构造对象类型(如String、Number)及基本类型(如string、number、boolean)作为class属性的持久化(String、Number是不可变的数据对象,没法直接作为[顶层数据类型](arkts-new-persistencev2.md#globalconnect顶层持久化数据类型及非顶层数据类型)进行持久化)。对于不支持的类型,会抛出运行时报错,从API version 23开始,将返回错误码[140103](../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/错误码/UI界面/状态管理错误码/errorcode-statemanagement.md#section140103-appstoragev2和persistencev2使用不支持的数据类型)。
174
+
175
+ 如下为新增globalConnect支持Array<ClassA>类型的持久化示例:
176
+
177
+ ```
178
+ 1. import { PersistenceV2, UIUtils } from '@kit.ArkUI';
179
+
180
+ 3. @ObservedV2
181
+ 4. class ClassA {
182
+ 5. @Trace public propA: string = '';
183
+ 6. @Trace public propB: string = '';
184
+
185
+ 8. public report(): string {
186
+ 9. return `${this.propA} - ${this.propB}`;
187
+ 10. }
188
+ 11. }
189
+
190
+ 13. @Entry
191
+ 14. @ComponentV2
192
+ 15. struct Comp {
193
+ 16. // 持久化顶层数据类型为Array<ClassA>的数据
194
+ 17. @Local arr: Array<ClassA> = PersistenceV2.globalConnect({
195
+ 18. type: Array<ClassA>,
196
+ 19. defaultCreator: () => UIUtils.makeObserved(new Array<ClassA>()),
197
+ 20. // 添加defaultSubCreator,通知状态管理框架如何创建数组项
198
+ 21. // 另外持久化的数据需要加上makeObserved,因为JSON对象本身没有观察能力,自动持久化会失败
199
+ 22. defaultSubCreator: () => UIUtils.makeObserved(new ClassA())
200
+ 23. })!;
201
+
202
+ 25. build() {
203
+ 26. Column() {
204
+ 27. Repeat(this.arr)
205
+ 28. .each(ri => {
206
+ 29. Row() {
207
+ 30. Text(`propA '${ri.item.propA}'`)
208
+ 31. Text(`propB '${ri.item.propB}'`)
209
+ 32. Text(`report?.() '${ri.item.report?.()}'`)
210
+ 33. }
211
+ 34. })
212
+ 35. // 点击'add item',显示`propA 'a' propB 'b'report?.'a' - 'b'`, 杀掉应用,再次进入,会显示上次的结果
213
+ 36. Button('add item')
214
+ 37. .onClick(() => {
215
+ 38. let temp: ClassA = new ClassA();
216
+ 39. temp.propA = 'a';
217
+ 40. temp.propB = 'b';
218
+ 41. this.arr.push(temp);
219
+ 42. })
220
+ 43. }
221
+ 44. }
222
+ 45. }
223
+ ```
224
+
225
+ [TopLevelArrayClassA.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/PersistenceV2/entry/src/main/ets/pages/TopLevelArrayClassA.ets#L16-L62)
226
+
227
+ 如下为globalConnect支持Date类型的持久化示例:
228
+
229
+ ```
230
+ 1. import { PersistenceV2, UIUtils } from '@kit.ArkUI';
231
+
232
+ 3. @Entry
233
+ 4. @ComponentV2
234
+ 5. struct Page1 {
235
+ 6. // 支持直接持久化Date类型的数据
236
+ 7. @Local date: Date = PersistenceV2.globalConnect({
237
+ 8. type: Date,
238
+ 9. defaultCreator: () => UIUtils.makeObserved(new Date())
239
+ 10. })!;
240
+
241
+ 12. build() {
242
+ 13. Column({ space: 40 }) {
243
+ 14. Text(`date: ${this.date.toISOString()}`)
244
+ 15. .fontSize(24)
245
+ 16. // 点击'date.setTime( Date.now() )', 杀掉应用,进入应用后,显示日期
246
+ 17. Button('date.setTime( Date.now() )')
247
+ 18. .onClick(() => {
248
+ 19. this.date.setTime(Date.now());
249
+ 20. })
250
+ 21. .fontSize(24)
251
+ 22. }
252
+ 23. .width('100%')
253
+ 24. }
254
+ 25. }
255
+ ```
256
+
257
+ [TopLevelDate.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/PersistenceV2/entry/src/main/ets/pages/TopLevelDate.ets#L16-L42)
258
+
259
+ 如下为globalConnect支持Number类型作为class子属性的持久化示例:
260
+
261
+ ```
262
+ 1. import { PersistenceV2 } from '@kit.ArkUI';
263
+
264
+ 3. @ObservedV2 class NumberClass {
265
+ 4. // Number类型不是顶层持久化数据类型,只能支持非顶层数据类型的持久化
266
+ 5. @Trace public value: Number = new Number(Infinity);
267
+ 6. }
268
+
269
+ 8. @Entry
270
+ 9. @ComponentV2
271
+ 10. struct Page1 {
272
+ 11. // Number类型只能作为NumberClass的子属性去持久化
273
+ 12. @Local number: NumberClass = PersistenceV2.globalConnect({
274
+ 13. type: NumberClass,
275
+ 14. defaultCreator: () => new NumberClass()
276
+ 15. })!;
277
+ 16. output: string[] = [];
278
+
279
+ 18. aboutToAppear(): void {
280
+ 19. this.output.push(`this.number.value: ${this.number.value}, is instanceof Number ${this.number.value instanceof Number}`);
281
+ 20. this.number.value = new Number(-this.number.value);
282
+ 21. }
283
+
284
+ 23. build() {
285
+ 24. Column() {
286
+ 25. Row() {
287
+ 26. // 第一次打开应用,界面显示'this.number.value: Infinity, is instanceof Number true'
288
+ 27. // 第二次打开应用,界面显示'this.number.value: -Infinity, is instanceof Number true'
289
+ 28. Text(this.output.join('\n\n'))
290
+ 29. .fontSize(24)
291
+ 30. }
292
+ 31. }
293
+ 32. .width('100%')
294
+ 33. }
295
+ 34. }
296
+ ```
297
+
298
+ [NonTopLevelNumberOfClass.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/PersistenceV2/entry/src/main/ets/pages/NonTopLevelNumberOfClass.ets#L16-L51)
299
+
300
+ 6、在API version 23以前,不支持循环引用对象的持久化。
301
+
302
+ * 在API version 23开始,提供globalConnect接口支持循环引用的对象持久化。
303
+
304
+ 如下为globalConnect支持循环引用的对象的持久化示例:
305
+
306
+ ```
307
+ 1. import { PersistenceV2 } from '@kit.ArkUI';
308
+
309
+ 3. @ObservedV2
310
+ 4. class ClassA {
311
+ 5. @Trace public value: string = 'a';
312
+ 6. @Trace public refB: ClassB | undefined;
313
+ 7. }
314
+
315
+ 9. @ObservedV2
316
+ 10. class ClassB {
317
+ 11. @Trace public value: string = 'b';
318
+ 12. @Trace public refA: ClassA | undefined;
319
+ 13. }
320
+
321
+ 15. @ObservedV2
322
+ 16. class ClassC {
323
+ 17. @Trace public value: string = 'c';
324
+ 18. @Trace public objA: ClassA = new ClassA();
325
+ 19. @Trace public objB: ClassB = new ClassB();
326
+
327
+ 21. // ClassC是循环引用对象
328
+ 22. constructor() {
329
+ 23. this.objA.refB = this.objB;
330
+ 24. this.objB.refA = this.objA;
331
+ 25. }
332
+ 26. }
333
+
334
+ 28. @Entry
335
+ 29. @ComponentV2
336
+ 30. struct Page1 {
337
+ 31. @Local test: ClassC = PersistenceV2.globalConnect({
338
+ 32. type: ClassC,
339
+ 33. defaultCreator: () => new ClassC()
340
+ 34. })!;
341
+ 35. output: string[] = [];
342
+
343
+ 37. aboutToAppear(): void {
344
+ 38. const refAValue = this.test.objA?.refB?.refA?.value;
345
+ 39. const refBValue = this.test.objB?.refA?.refB?.value;
346
+ 40. this.output.push(`${refAValue}, ${refBValue}`);
347
+ 41. this.test.objA.value += 'a';
348
+ 42. this.test.objB.value += 'b';
349
+ 43. }
350
+
351
+ 45. build() {
352
+ 46. Column() {
353
+ 47. Row() {
354
+ 48. // 第一次打开应用,界面显示'a, b'
355
+ 49. // 第二次打开应用,界面显示'aa, bb'
356
+ 50. Text(this.output.join('\n\n'))
357
+ 51. .fontSize(24)
358
+ 52. }
359
+ 53. }
360
+ 54. .width('100%')
361
+ 55. }
362
+ 56. }
363
+ ```
364
+
365
+ [CircularReferenceOfObject.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/PersistenceV2/entry/src/main/ets/pages/CircularReferenceOfObject.ets#L16-L73)
366
+
367
+ 7、只有[@Trace](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace)的数据改变会触发自动持久化,如V1状态变量、[@Observed](../../../状态管理(V1)/管理组件拥有的状态/@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化/arkts-observed-and-objectlink.md)对象、普通数据的改变不会触发持久化。
368
+
369
+ 8、connect和globalConnect不建议混用,如果混用,key不能一样,否则应用crash,从API version 23开始,将返回错误码[140105](../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/错误码/UI界面/状态管理错误码/errorcode-statemanagement.md#section140105-persistencev2混用connect和globalconnect并使用相同的key)。
370
+
371
+ 9、PersistenceV2必须与UI实例关联,持久化操作需在UI实例初始化完成后调用(即[loadContent](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/窗口管理/@ohos.window (窗口)/Interface (WindowStage)/arkts-apis-window-windowstage.md#loadcontent9>)回调触发后)。
372
+
373
+ ```
374
+ 1. // EntryAbility.ets
375
+ 2. // 以下为代码片段,需要开发者自己在EntryAbility.ets中补全
376
+ 3. import { PersistenceV2 } from '@kit.ArkUI';
377
+
378
+ 5. // 在EntryAbility外部定义class
379
+ 6. @ObservedV2
380
+ 7. class Storage {
381
+ 8. @Trace isPersist: boolean = false;
382
+ 9. }
383
+
384
+ 11. // 在onWindowStageCreate的loadContent回调中调用PersistenceV2
385
+ 12. onWindowStageCreate(windowStage: window.WindowStage): void {
386
+ 13. windowStage.loadContent('pages/Index', (err) => {
387
+ 14. if (err.code) {
388
+ 15. return;
389
+ 16. }
390
+ 17. PersistenceV2.connect(Storage, () => new Storage());
391
+ 18. });
392
+ 19. }
393
+ ```
394
+
395
+ 10、如果开发者对数据持久化能力有较强的诉求,例如持久化时机,建议使用[Preferences](<../../../../../../ArkData(方舟数据管理)/应用数据持久化/通过用户首选项实现数据持久化 (CC++)/preferences-guidelines.md>)进行数据持久化。注意:不允许混用PersistenceV2和Preferences,因为Preferences存储的数据不会有状态变量信息,反序列化的数据不能触发PersistenceV2的自动化存储。
396
+
397
+ 11、当开发者使用globalConnect持久化数据,从磁盘读取数据时,需要保证key数据在持久化前后类型一致。从API version 23开始,将返回错误码[140107](../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/错误码/UI界面/状态管理错误码/errorcode-statemanagement.md#section140107-appstoragev2和persistencev2数据类型不匹配)。
398
+
399
+ 12、globalConnect仅支持设置EL1-EL5加密级别,否则会抛出运行时异常,从API version 23开始,将返回错误码[140106](../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/错误码/UI界面/状态管理错误码/errorcode-statemanagement.md#section140106-使用persistencev2存储数据到不支持的加密级别),示例见[使用globalConnect存储数据](arkts-new-persistencev2.md#使用globalconnect存储数据)。
400
+
401
+ 13、不支持在使用connect或globalConnect的类中使用[@Computed](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-computed)。@Computed为只读属性,不支持赋值操作,因此会导致反序列化失败。
402
+
403
+ ## globalConnect支持的类型
404
+
405
+ ### globalConnect顶层持久化数据类型及非顶层数据类型
406
+
407
+ 在API version 23以前,持久化的顶层数据类型必须是用户自定义的class对象,不支持容器类型(如Array、Set、Map,Date)。在API version 23开始,持久化的顶层数据类型可以是用户自定义的class,也可以是容器类型。非顶层数据类型,是指定义在用户自定义class属性的类型。
408
+
409
+ 如下示例中,Array<ClassA>是顶层持久化数据类型, 可作为globalConnect的直接返回值类型,collections.Map是CollectionMapClass类中属性的类型,属于非顶层持久化的数据类型。
410
+
411
+ ```
412
+ 1. class ClassA {
413
+ 2. propA: number;
414
+
415
+ 4. }
416
+ 5. @Sendable
417
+ 6. class CollectionMapClass {
418
+ 7. // 用户自定义的class中属性类型为collections.Map,非顶层持久化数据类型
419
+ 8. value = new collections.Map<number, number>([]);
420
+ 9. }
421
+
422
+ 11. @ComponentV2
423
+ 12. struct Page1 {
424
+ 13. // 顶层持久化数据类型为Array<ClassA>
425
+ 14. @Local arr: Array<ClassA> = PersistenceV2.globalConnect({
426
+ 15. type: Array<ClassA>,
427
+ 16. defaultCreator: () => UIUtils.makeObserved(new Array<ClassA>()),
428
+ 17. // 添加defaultSubCreator,通知状态管理框架如何创建数组项
429
+ 18. // 另外持久化后的数据需要加上makeObserved,否则会持久化失败
430
+ 19. defaultSubCreator: () => UIUtils.makeObserved(new ClassA())
431
+ 20. })!;
432
+
433
+ 22. // 顶层持久化数据类型为用户自定义的class,collections.Map为非顶层持久化数据类型
434
+ 23. collectionMap: CollectionMapClass = PersistenceV2.globalConnect({
435
+ 24. type: CollectionMapClass,
436
+ 25. defaultCreator: () => new CollectionMapClass()
437
+ 26. })!
438
+ 27. // ...
439
+ 28. }
440
+ ```
441
+
442
+ ### globalConnect用户自定义class对象属性支持的类型
443
+
444
+ 用户自定义class对象的属性可以使用以下类型:boolean、number、string、undefined、null、Object、Date、Number、Boolean、String以及自定义类class。还支持以下集合类型:Array、Map、Set。
445
+
446
+ ```
447
+ 1. // 观察类的@Trace属性支持上述所有类型
448
+ 2. @ObservedV2
449
+ 3. class ClassA {
450
+ 4. // VType是上述列举的类型
451
+ 5. @Trace propA: VType;
452
+ 6. }
453
+
454
+ 8. @ComponentV2 struct Comp {
455
+ 9. @Local obsObj : ClassA = PersistenceV2.globalConnect({
456
+ 10. type: ClassA,
457
+ 11. defaultCreator: () => new ClassA()
458
+ 12. })
459
+ 13. // ...
460
+ 14. }
461
+ ```
462
+
463
+ 用户自定义class类型的属性必须使用@Type装饰器装饰,且其class属性值必须严格为@Type中指定类的实例。
464
+
465
+ ```
466
+ 1. class ClassA {
467
+ 2. // ...
468
+ 3. }
469
+ 4. class PersistClass {
470
+ 5. @Type(ClassA)
471
+ 6. propA: ClassA = new ClassA();
472
+ 7. }
473
+ ```
474
+
475
+ ### globalConnect支持集合的类型
476
+
477
+ 集合类型是指Array<V>、Map<K, V>、Set<V>、collections.Array<V>、collections.Map<K, V>、collections.Set<V>。
478
+
479
+ 其中,Map<K, V>和collections.Map<k, V>中的key值类型(K)是指string或number类型。
480
+
481
+ Array<V>、Map<K, V>和 Set<V>中,V的类型包括:boolean、number、string、Date、Number、Boolean、String、interface类型和class类型。
482
+
483
+ collections.Array<V>、collections.Map<K, V>、collections.Set<V>要求V的类型必须是@Sendable类型的数据(boolean、number、string类型)。
484
+
485
+ 如下展示globalConnect持久化Array<ClassA>的示例:
486
+
487
+ ```
488
+ 1. import { PersistenceV2, UIUtils } from '@kit.ArkUI';
489
+
490
+ 3. class ClassA {
491
+ 4. public propA: number = 0;
492
+ 5. public classAToString() : string {
493
+ 6. return this.propA.toString()
494
+ 7. }
495
+ 8. }
496
+
497
+ 10. @Entry
498
+ 11. @ComponentV2
499
+ 12. struct Page1 {
500
+ 13. @Local arr: Array<ClassA> = PersistenceV2.globalConnect({
501
+ 14. type: Array<ClassA>,
502
+ 15. defaultCreator: () => UIUtils.makeObserved(new Array<ClassA>()),
503
+ 16. // 添加defaultSubCreator,通知状态管理框架如何创建ClassA对象
504
+ 17. // 另外持久化后的数据需要加上makeObserved,否则会持久化失败
505
+ 18. defaultSubCreator: () => UIUtils.makeObserved(new ClassA())
506
+ 19. })!;
507
+
508
+ 21. build() {
509
+ 22. Column({ space: 10 }) {
510
+ 23. Column({ space: 0 }) {
511
+ 24. Repeat(this.arr)
512
+ 25. .each(ri => {
513
+ 26. Row() {
514
+ 27. Text(`Item: `)
515
+ 28. Text(ri.item.classAToString ? ri.item.classAToString(): `classAToString() missing from object, propA: ${ri.item.propA}`)
516
+ 29. }
517
+ 30. })
518
+ 31. .key((item: ClassA, index: number) => `${index} - ${item.propA}`)
519
+ 32. }
520
+
521
+ 34. Divider().width('100%')
522
+ 35. // 点击'array.push(0)',重启应用,Repeat数组项是:1, 2, 0
523
+ 36. Button('array.push(0)')
524
+ 37. .onClick(() => {
525
+ 38. let temp = new ClassA();
526
+ 39. temp.propA = 0;
527
+ 40. this.arr.push(UIUtils.makeObserved(temp));
528
+ 41. })
529
+ 42. .fontSize(24)
530
+ 43. // 点击'array.pop()',重启应用,Repeat数组项是:1, 2
531
+ 44. Button('array.pop()')
532
+ 45. .onClick(() => {
533
+ 46. this.arr.pop();
534
+ 47. })
535
+ 48. .fontSize(24)
536
+ 49. // 点击'array.splice(0)',重启应用,Repeat数组项为空
537
+ 50. Button('array.splice(0)')
538
+ 51. .onClick(() => {
539
+ 52. this.arr.splice(0);
540
+ 53. })
541
+ 54. .fontSize(24)
542
+ 55. // 点击'splice(1, 0, random)',重启应用:Repeat组件再次显示相同的数组项
543
+ 56. Button('array.splice(1, 0, random)')
544
+ 57. .onClick(() => {
545
+ 58. let temp = new ClassA();
546
+ 59. temp.propA = Math.round(100 * Math.random());
547
+ 60. this.arr.splice(1, 0, UIUtils.makeObserved(temp));
548
+ 61. })
549
+ 62. .fontSize(24)
550
+ 63. // 点击'array.splice(0, 2, random, random)',前两个数组项目被替换,记录下来
551
+ 64. // 重启应用:Repeat组件再次显示数组项
552
+ 65. Button('array.splice(0, 2, random, random)')
553
+ 66. .onClick(() => {
554
+ 67. let tempA = new ClassA();
555
+ 68. tempA.propA = Math.round(100 * Math.random());
556
+ 69. this.arr.splice(2, 2,
557
+ 70. UIUtils.makeObserved(tempA),
558
+ 71. UIUtils.makeObserved(tempA));
559
+ 72. })
560
+ 73. .fontSize(24)
561
+ 74. // 点击'array.sort', 对数组项升序排列,重启应用,Repeat组件展示升序数组
562
+ 75. Button('array.sort')
563
+ 76. .onClick(() => {
564
+ 77. this.arr.sort((tempA, tempB)=> tempA.propA - tempB.propA);
565
+ 78. })
566
+ 79. .fontSize(24)
567
+ 80. // 点击'array.reverse', 对数组项降序排列,重启应用,Repeat组件展示降序数组
568
+ 81. Button('array.reverse')
569
+ 82. .onClick(() => {
570
+ 83. this.arr.reverse();
571
+ 84. })
572
+ 85. .fontSize(24)
573
+ 86. }
574
+ 87. .width('100%')
575
+ 88. }
576
+ 89. }
577
+ ```
578
+
579
+ [TopLevelArrayClassAAPIs.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/PersistenceV2/entry/src/main/ets/pages/TopLevelArrayClassAAPIs.ets#L16-L106)
580
+
581
+ ## 使用场景
582
+
583
+ ### 在两个页面之间存储数据
584
+
585
+ 数据页面
586
+
587
+ ```
588
+ 1. // Sample.ets
589
+ 2. import { Type } from '@kit.ArkUI';
590
+
591
+ 4. // 数据中心
592
+ 5. @ObservedV2
593
+ 6. class SampleChild {
594
+ 7. @Trace public p1: number = 0;
595
+ 8. public p2: number = 10;
596
+ 9. }
597
+
598
+ 11. @ObservedV2
599
+ 12. export class Sample {
600
+ 13. // 对于复杂对象需要@Type修饰,确保序列化成功
601
+ 14. @Type(SampleChild)
602
+ 15. @Trace public f: SampleChild = new SampleChild();
603
+ 16. }
604
+ ```
605
+
606
+ [Sample.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ParadigmStateManagement/entry/src/main/ets/pages/persistenceV2/Sample.ets#L16-L34)
607
+
608
+ 页面1
609
+
610
+ ```
611
+ 1. // Page1.ets
612
+ 2. import { PersistenceV2 } from '@kit.ArkUI';
613
+ 3. import { Sample } from '../Sample';
614
+ 4. import { hilog } from '@kit.PerformanceAnalysisKit';
615
+
616
+ 6. const DOMAIN = 0x0000;
617
+
618
+ 8. // 接受序列化失败的回调
619
+ 9. PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
620
+ 10. hilog.error(DOMAIN, 'testTag', '%{public}s', `error key: ${key}, reason: ${reason}, message: ${msg}`);
621
+ 11. });
622
+
623
+ 13. @Entry
624
+ 14. @ComponentV2
625
+ 15. struct Page1 {
626
+ 16. // 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联
627
+ 17. // 对于需要换connect对象的prop属性,需要加@Local修饰(不建议对属性换connect的对象)
628
+ 18. @Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;
629
+ 19. pageStack: NavPathStack = new NavPathStack();
630
+
631
+ 21. build() {
632
+ 22. Navigation(this.pageStack) {
633
+ 23. Column() {
634
+ 24. Button('Go to page2')
635
+ 25. .onClick(() => {
636
+ 26. this.pageStack.pushPathByName('Page2', null);
637
+ 27. })
638
+
639
+ 29. Button('Page1 connect the key Sample')
640
+ 30. .onClick(() => {
641
+ 31. // 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联
642
+ 32. // 不建议对prop属性换connect的对象
643
+ 33. this.prop = PersistenceV2.connect(Sample, 'Sample', () => new Sample())!;
644
+ 34. })
645
+
646
+ 36. Button('Page1 remove the key Sample')
647
+ 37. .onClick(() => {
648
+ 38. // 从PersistenceV2中删除后,prop将不会再与key为Sample的值关联
649
+ 39. PersistenceV2.remove(Sample);
650
+ 40. })
651
+
652
+ 42. Button('Page1 save the key Sample')
653
+ 43. .onClick(() => {
654
+ 44. // 如果处于connect状态,持久化key为Sample的键值对
655
+ 45. PersistenceV2.save(Sample);
656
+ 46. })
657
+
658
+ 48. Text(`Page1 add 1 to prop.p1: ${this.prop.f.p1}`)
659
+ 49. .fontSize(30)
660
+ 50. .onClick(() => {
661
+ 51. this.prop.f.p1++;
662
+ 52. })
663
+
664
+ 54. Text(`Page1 add 1 to prop.p2: ${this.prop.f.p2}`)
665
+ 55. .fontSize(30)
666
+ 56. .onClick(() => {
667
+ 57. // 页面不刷新,但是p2的值改变了
668
+ 58. this.prop.f.p2++;
669
+ 59. })
670
+
671
+ 61. // 获取当前PersistenceV2里面的所有key
672
+ 62. Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`)
673
+ 63. .fontSize(30)
674
+ 64. }
675
+ 65. }
676
+ 66. }
677
+ 67. }
678
+ ```
679
+
680
+ [Page1.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ParadigmStateManagement/entry/src/main/ets/pages/persistenceV2/page/Page1.ets#L16-L84)
681
+
682
+ 页面2
683
+
684
+ ```
685
+ 1. // Page2.ets
686
+ 2. import { PersistenceV2 } from '@kit.ArkUI';
687
+ 3. import { Sample } from '../Sample';
688
+
689
+ 5. @Builder
690
+ 6. export function Page2Builder() {
691
+ 7. Page2()
692
+ 8. }
693
+
694
+ 10. @ComponentV2
695
+ 11. struct Page2 {
696
+ 12. // 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联
697
+ 13. // 对于需要换connect对象的prop属性,需要加@Local修饰(不建议对属性换connect的对象)
698
+ 14. @Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;
699
+ 15. pathStack: NavPathStack = new NavPathStack();
700
+
701
+ 17. build() {
702
+ 18. NavDestination() {
703
+ 19. Column() {
704
+ 20. Button('Page2 connect the key Sample1')
705
+ 21. .onClick(() => {
706
+ 22. // 在PersistenceV2中创建一个key为Sample1的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联
707
+ 23. // 不建议对prop属性换connect的对象
708
+ 24. this.prop = PersistenceV2.connect(Sample, 'Sample1', () => new Sample())!;
709
+ 25. })
710
+
711
+ 27. Text(`Page2 add 1 to prop.p1: ${this.prop.f.p1}`)
712
+ 28. .fontSize(30)
713
+ 29. .onClick(() => {
714
+ 30. this.prop.f.p1++;
715
+ 31. })
716
+
717
+ 33. Text(`Page2 add 1 to prop.p2: ${this.prop.f.p2}`)
718
+ 34. .fontSize(30)
719
+ 35. .onClick(() => {
720
+ 36. // 页面不刷新,但是p2的值改变了;只有重新初始化才会改变
721
+ 37. this.prop.f.p2++;
722
+ 38. })
723
+
724
+ 40. // 获取当前PersistenceV2里面的所有key
725
+ 41. Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`)
726
+ 42. .fontSize(30)
727
+ 43. }
728
+ 44. }
729
+ 45. .onReady((context: NavDestinationContext) => {
730
+ 46. this.pathStack = context.pathStack;
731
+ 47. })
732
+ 48. }
733
+ 49. }
734
+ ```
735
+
736
+ [Page2.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ParadigmStateManagement/entry/src/main/ets/pages/persistenceV2/page/Page2.ets#L16-L66)
737
+
738
+ 使用Navigation时,需要添加配置系统路由表文件src/main/resources/base/profile/route\_map.json,并替换pageSourceFile为Page2页面的路径,并且在module.json5中添加:"routerMap": "$profile:route\_map"。
739
+
740
+ ```
741
+ 1. {
742
+ 2. "routerMap": [
743
+ 3. {
744
+ 4. "name": "Page2",
745
+ 5. "pageSourceFile": "src/main/ets/pages/Page2.ets",
746
+ 6. "buildFunction": "Page2Builder",
747
+ 7. "data": {
748
+ 8. "description" : "PersistenceV2 example"
749
+ 9. }
750
+ 10. }
751
+ 11. ]
752
+ 12. }
753
+ ```
754
+
755
+ ### 使用globalConnect存储数据
756
+
757
+ ```
758
+ 1. import { PersistenceV2, Type, ConnectOptions } from '@kit.ArkUI';
759
+ 2. import { contextConstant } from '@kit.AbilityKit';
760
+ 3. import { hilog } from '@kit.PerformanceAnalysisKit';
761
+
762
+ 5. const DOMAIN = 0x0000;
763
+ 6. // 接受序列化失败的回调
764
+ 7. PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
765
+ 8. hilog.error(DOMAIN, 'testTag', '%{public}s', `error key: ${key}, reason: ${reason}, message: ${msg}`);
766
+ 9. });
767
+
768
+ 11. @ObservedV2
769
+ 12. class SampleChild {
770
+ 13. @Trace public childId: number = 0;
771
+ 14. public groupId: number = 1;
772
+ 15. }
773
+
774
+ 17. @ObservedV2
775
+ 18. export class SampleGlobalConnect {
776
+ 19. // 对于复杂对象需要@Type修饰,确保序列化成功
777
+ 20. @Type(SampleChild)
778
+ 21. @Trace public father: SampleChild = new SampleChild();
779
+ 22. }
780
+
781
+ 24. @Entry
782
+ 25. @ComponentV2
783
+ 26. struct Page1 {
784
+ 27. @Local refresh: number = 0;
785
+ 28. // key不传入尝试用为type的name作为key,加密参数不传入默认加密等级为EL2
786
+ 29. @Local p: SampleGlobalConnect =
787
+ 30. PersistenceV2.globalConnect({ type: SampleGlobalConnect, defaultCreator: () => new SampleGlobalConnect() })!;
788
+ 31. // 使用key:global1连接,传入加密等级为EL1
789
+ 32. @Local p1: SampleGlobalConnect = PersistenceV2.globalConnect({
790
+ 33. type: SampleGlobalConnect,
791
+ 34. key: 'global1',
792
+ 35. defaultCreator: () => new SampleGlobalConnect(),
793
+ 36. areaMode: contextConstant.AreaMode.EL1
794
+ 37. })!;
795
+ 38. // 使用key:global2连接,使用构造函数形式,加密参数不传入默认加密等级为EL2
796
+ 39. options: ConnectOptions<SampleGlobalConnect> =
797
+ 40. { type: SampleGlobalConnect, key: 'global2', defaultCreator: () => new SampleGlobalConnect() };
798
+ 41. @Local p2: SampleGlobalConnect = PersistenceV2.globalConnect(this.options)!;
799
+ 42. // 使用key:global3连接,直接写加密数值,范围只能在0-4,否则运行会crash,例如加密设置为EL3
800
+ 43. @Local p3: SampleGlobalConnect = PersistenceV2.globalConnect({
801
+ 44. type: SampleGlobalConnect,
802
+ 45. key: 'global3',
803
+ 46. defaultCreator: () => new SampleGlobalConnect(),
804
+ 47. areaMode: 3
805
+ 48. })!;
806
+
807
+ 50. build() {
808
+ 51. Column() {
809
+ 52. // 显示数据
810
+ 53. // 被@Trace修饰的数据可以自动持久化进磁盘
811
+ 54. Text('Key SampleGlobalConnect: ' + this.p.father.childId.toString())
812
+ 55. .onClick(() => {
813
+ 56. this.p.father.childId += 1;
814
+ 57. })
815
+ 58. .fontSize(25)
816
+ 59. .fontColor(Color.Red)
817
+ 60. Text('Key global1: ' + this.p1.father.childId.toString())
818
+ 61. .onClick(() => {
819
+ 62. this.p1.father.childId += 1;
820
+ 63. })
821
+ 64. .fontSize(25)
822
+ 65. .fontColor(Color.Red)
823
+ 66. Text('Key global2: ' + this.p2.father.childId.toString())
824
+ 67. .onClick(() => {
825
+ 68. this.p2.father.childId += 1;
826
+ 69. })
827
+ 70. .fontSize(25)
828
+ 71. .fontColor(Color.Red)
829
+ 72. Text('Key global3: ' + this.p3.father.childId.toString())
830
+ 73. .onClick(() => {
831
+ 74. this.p3.father.childId += 1;
832
+ 75. })
833
+ 76. .fontSize(25)
834
+ 77. .fontColor(Color.Red)
835
+ 78. // keys接口
836
+ 79. // keys本身不会刷新,需要借助状态变量刷新
837
+ 80. Text('Persist keys: ' + PersistenceV2.keys().toString() + ' refresh: ' + this.refresh)
838
+ 81. .onClick(() => {
839
+ 82. this.refresh += 1;
840
+ 83. })
841
+ 84. .fontSize(25)
842
+
843
+ 86. // remove接口
844
+ 87. Text('Remove key SampleGlobalConnect: ' + 'refresh: ' + this.refresh)
845
+ 88. .onClick(() => {
846
+ 89. // 删除这个key,会导致和p失去联系,之后即使reconnect,p也无法存储
847
+ 90. PersistenceV2.remove(SampleGlobalConnect);
848
+ 91. this.refresh += 1;
849
+ 92. })
850
+ 93. .fontSize(25)
851
+ 94. Text('Remove key global1: ' + 'refresh: ' + this.refresh)
852
+ 95. .onClick(() => {
853
+ 96. // 删除这个key,会导致和p1失去联系,之后即使reconnect,p1也无法存储
854
+ 97. PersistenceV2.remove('global1');
855
+ 98. this.refresh += 1;
856
+ 99. })
857
+ 100. .fontSize(25)
858
+ 101. Text('Remove key global2: ' + 'refresh: ' + this.refresh)
859
+ 102. .onClick(() => {
860
+ 103. // 删除这个key,会导致和p2失去联系,之后即使reconnect,p2也无法存储
861
+ 104. PersistenceV2.remove('global2');
862
+ 105. this.refresh += 1;
863
+ 106. })
864
+ 107. .fontSize(25)
865
+ 108. Text('Remove key global3: ' + 'refresh: ' + this.refresh)
866
+ 109. .onClick(() => {
867
+ 110. // 删除这个key,会导致和p3失去联系,之后即使reconnect,p3也无法存储
868
+ 111. PersistenceV2.remove('global3');
869
+ 112. this.refresh += 1;
870
+ 113. })
871
+ 114. .fontSize(25)
872
+ 115. // reConnect
873
+ 116. // 重新连接也无法和之前的状态变量建立联系,因此无法保存数据
874
+ 117. Text('ReConnect key global2: ' + 'refresh: ' + this.refresh)
875
+ 118. .onClick(() => {
876
+ 119. // 此时会重新存储一个key为global2的变量,但该变量与p2无关
877
+ 120. PersistenceV2.globalConnect(this.options);
878
+ 121. this.refresh += 1;
879
+ 122. })
880
+ 123. .fontSize(25)
881
+
882
+ 125. // save接口
883
+ 126. Text('not save key SampleGlobalConnect: ' + this.p.father.groupId.toString() + ' refresh: ' + this.refresh)
884
+ 127. .onClick(() => {
885
+ 128. // 未被@Trace保存的对象无法自动存储
886
+ 129. this.p.father.groupId += 1;
887
+ 130. this.refresh += 1;
888
+ 131. })
889
+ 132. .fontSize(25)
890
+ 133. Text('save key SampleGlobalConnect: ' + this.p.father.groupId.toString() + ' refresh: ' + this.refresh)
891
+ 134. .onClick(() => {
892
+ 135. // 未被@Trace保存的对象无法自动存储,需要调用save存储
893
+ 136. this.p.father.groupId += 1;
894
+ 137. PersistenceV2.save(SampleGlobalConnect);
895
+ 138. this.refresh += 1;
896
+ 139. })
897
+ 140. .fontSize(25)
898
+ 141. }
899
+ 142. .width('100%')
900
+ 143. }
901
+ 144. }
902
+ ```
903
+
904
+ [PersistenceV2GlobalConnect.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ParadigmStateManagement/entry/src/main/ets/pages/persistenceV2/PersistenceV2GlobalConnect.ets#L15-L160)
905
+
906
+ ### 在不同的module中使用connect和globalConnect
907
+
908
+ **connect的存储路径需要注意以下两点:**
909
+
910
+ 1、connect使用module级别的存储路径,以最先启动的module的路径作为存储路径,从内存回写磁盘时会回写到第一个连接该module的路径。应用如果之后先从另一个module启动,则会以新module的路径作为存储路径。
911
+
912
+ 2、当不同module使用相同的key时,哪个module先启动,数据就为哪个module中保存的键值对,回写到对应的module中。
913
+
914
+ **globalConnect的存储路径需要注意:**
915
+
916
+ globalConnect虽然是应用级别的路径,但是可以设置不同的加密分区,不同加密分区即代表不同的存储路径。connect不支持设置加密分区,但是module自身切换加密级别时,module存储路径也会切换成对应加密分区路径。
917
+
918
+ 示例代码如下:开发者需要在项目基础上,新建一个module,并按照示例代码跳转到新module中。
919
+
920
+ ```
921
+ 1. // 模块1
922
+ 2. import { PersistenceV2, Type } from '@kit.ArkUI';
923
+ 3. import { common, Want } from '@kit.AbilityKit';
924
+ 4. import { hilog } from '@kit.PerformanceAnalysisKit';
925
+ 5. import { contextConstant } from '@kit.AbilityKit';
926
+
927
+ 7. const DOMAIN = 0x0000;
928
+
929
+ 9. // 接受序列化失败的回调
930
+ 10. PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
931
+ 11. hilog.error(DOMAIN, 'testTag', '%{public}s', `error key: ${key}, reason: ${reason}, message: ${msg}`);
932
+ 12. });
933
+
934
+ 14. @ObservedV2
935
+ 15. class SampleChild {
936
+ 16. @Trace public childId: number = 0;
937
+ 17. public groupId: number = 1;
938
+ 18. }
939
+
940
+ 20. @ObservedV2
941
+ 21. export class Sample {
942
+ 22. // 对于复杂对象需要@Type修饰,确保序列化成功
943
+ 23. @Type(SampleChild)
944
+ 24. @Trace public father: SampleChild = new SampleChild();
945
+ 25. }
946
+
947
+ 27. @Entry
948
+ 28. @ComponentV2
949
+ 29. struct Page1 {
950
+ 30. @Local refresh: number = 0;
951
+ 31. // 使用key:globalConnect1连接,传入加密等级为EL1
952
+ 32. @Local p1: Sample =
953
+ 33. PersistenceV2.globalConnect({
954
+ 34. type: Sample,
955
+ 35. key: 'globalConnect1',
956
+ 36. defaultCreator: () => new Sample(),
957
+ 37. areaMode: contextConstant.AreaMode.EL1
958
+ 38. })!;
959
+ 39. // 使用key:connect2连接,使用构造函数形式,加密参数不传入默认加密等级为EL2
960
+ 40. @Local p2: Sample = PersistenceV2.connect(Sample, 'connect2', () => new Sample())!;
961
+ 41. private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
962
+
963
+ 43. build() {
964
+ 44. Column() {
965
+ 45. // 显示数据
966
+ 46. Text('Key globalConnect1: ' + this.p1.father.childId.toString())
967
+ 47. .onClick(() => {
968
+ 48. this.p1.father.childId += 1;
969
+ 49. })
970
+ 50. .fontSize(25)
971
+ 51. .fontColor(Color.Red)
972
+ 52. Text('Key connect2: ' + this.p2.father.childId.toString())
973
+ 53. .onClick(() => {
974
+ 54. this.p2.father.childId += 1;
975
+ 55. })
976
+ 56. .fontSize(25)
977
+ 57. .fontColor(Color.Red)
978
+
979
+ 59. // 跳转
980
+ 60. Button('Jump to newModule')
981
+ 61. .onClick(() => { // 不同module之间使用,建议使用globalConnect
982
+ 62. let want: Want = {
983
+ 63. deviceId: '', // deviceId为空代表本设备
984
+ 64. bundleName: 'com.samples.paradigmstatemanagement', // 在app.json5中查看
985
+ 65. moduleName: 'demo', // 在需要跳转的module的module.json5中查看,非必选参数
986
+ 66. abilityName: 'NewModuleAbility', // 跳转启动的ability,在需要跳转的module的module.json5中查看
987
+ 67. uri: 'src/main/ets/pages/Index'
988
+ 68. };
989
+ 69. // context为调用方UIAbility的UIAbilityContext
990
+ 70. this.context.startAbility(want).then(() => {
991
+ 71. hilog.info(DOMAIN, 'testTag', '%{public}s', 'start ability success');
992
+ 72. }).catch((err: Error) => {
993
+ 73. hilog.error(DOMAIN, 'testTag', '%{public}s',
994
+ 74. `start ability failed. code is ${err.name}, message is ${err.message}`);
995
+ 75. });
996
+ 76. })
997
+ 77. }
998
+ 78. .width('100%')
999
+ 79. .borderWidth(3)
1000
+ 80. .borderColor(Color.Blue)
1001
+ 81. .margin({ top: 5, bottom: 5 })
1002
+ 82. }
1003
+ 83. }
1004
+ ```
1005
+
1006
+ [PersistenceV2ModuleConnectStorage1.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ParadigmStateManagement/entry/src/main/ets/pages/persistenceV2/PersistenceV2ModuleConnectStorage1.ets#L16-L100)
1007
+
1008
+ ```
1009
+ 1. // 模块2
1010
+ 2. import { PersistenceV2, Type } from '@kit.ArkUI';
1011
+ 3. import { hilog } from '@kit.PerformanceAnalysisKit';
1012
+ 4. import { contextConstant } from '@kit.AbilityKit';
1013
+
1014
+ 6. const DOMAIN = 0x0000;
1015
+ 7. // 接受序列化失败的回调
1016
+ 8. PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
1017
+ 9. hilog.error(DOMAIN, 'testTag', '%{public}s', `error key: ${key}, reason: ${reason}, message: ${msg}`);
1018
+ 10. });
1019
+
1020
+ 12. @ObservedV2
1021
+ 13. class SampleChild {
1022
+ 14. @Trace public childId: number = 0;
1023
+ 15. public groupId: number = 1;
1024
+ 16. }
1025
+
1026
+ 18. @ObservedV2
1027
+ 19. export class Sample {
1028
+ 20. // 对于复杂对象需要@Type修饰,确保序列化成功
1029
+ 21. @Type(SampleChild)
1030
+ 22. @Trace public father: SampleChild = new SampleChild();
1031
+ 23. }
1032
+
1033
+ 25. @Entry
1034
+ 26. @ComponentV2
1035
+ 27. struct Page1 {
1036
+ 28. @Local a: number = 0;
1037
+ 29. // 使用key:globalConnect1连接,传入加密等级为EL1
1038
+ 30. @Local p1: Sample =
1039
+ 31. PersistenceV2.globalConnect({ type: Sample, key: 'globalConnect1', defaultCreator: () => new Sample(), areaMode: contextConstant.AreaMode.EL1 })!;
1040
+ 32. // 使用key:connect2连接,使用构造函数形式,加密参数不传入默认加密等级为EL2
1041
+ 33. @Local p2: Sample = PersistenceV2.connect(Sample, 'connect2', () => new Sample())!;
1042
+
1043
+ 35. build() {
1044
+ 36. Column() {
1045
+ 37. // 显示数据
1046
+ 38. Text('Key globalConnect1: ' + this.p1.father.childId.toString())
1047
+ 39. .onClick(() => {
1048
+ 40. this.p1.father.childId += 1;
1049
+ 41. })
1050
+ 42. .fontSize(25)
1051
+ 43. .fontColor(Color.Red)
1052
+ 44. Text('Key connect2: ' + this.p2.father.childId.toString())
1053
+ 45. .onClick(() => {
1054
+ 46. this.p2.father.childId += 1;
1055
+ 47. })
1056
+ 48. .fontSize(25)
1057
+ 49. .fontColor(Color.Red)
1058
+ 50. }
1059
+ 51. .width('100%')
1060
+ 52. }
1061
+ 53. }
1062
+ ```
1063
+
1064
+ [Index.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ParadigmStateManagement/demo/src/main/ets/pages/Index.ets#L16-L70)
1065
+
1066
+ 当开发者对newModule使用不同启动方式会有以下现象:
1067
+
1068
+ * 开发者直接启动newModule,分别修改globalConnect1和connect2绑定的变量,例如将childId都改成5。
1069
+ * 应用退出并清空后台,启动模块entry,通过跳转按键启动newModule,会发现globalConnect1值为5,而connect2值为0未修改。
1070
+ * globalConnect为应用级别存储,对于一个key,整个应用在对应加密分区只有一份存储路径;connect为module级别的存储路径,会因为module的启动方式不同而在各自的加密分区对应不同的存储路径。
1071
+
1072
+ ## 使用建议
1073
+
1074
+ 建议开发者使用新接口globalConnect创建和获取数据。globalConnect的存储规格和内存规格一致,对于应用只有一份,并且支持设置加密级别,不需要去切换ability的加密才能设置数据的加密级别。当然如果开发者应用不涉及多模块,保持使用connect也不会有影响。
1075
+
1076
+ ### connect向globalConnect迁移实现
1077
+
1078
+ ```
1079
+ 1. // 使用connect存储数据
1080
+ 2. import { PersistenceV2, Type } from '@kit.ArkUI';
1081
+ 3. import { hilog } from '@kit.PerformanceAnalysisKit';
1082
+
1083
+ 5. const DOMAIN = 0x0000;
1084
+
1085
+ 7. // 接受序列化失败的回调
1086
+ 8. PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
1087
+ 9. hilog.error(DOMAIN, 'testTag', '%{public}s', `error key: ${key}, reason: ${reason}, message: ${msg}`);
1088
+ 10. });
1089
+
1090
+ 12. @ObservedV2
1091
+ 13. class SampleChild {
1092
+ 14. @Trace public childId: number = 0;
1093
+ 15. public groupId: number = 1;
1094
+ 16. }
1095
+
1096
+ 18. @ObservedV2
1097
+ 19. export class Sample {
1098
+ 20. // 对于复杂对象需要@Type修饰,确保序列化成功
1099
+ 21. @Type(SampleChild)
1100
+ 22. @Trace public father: SampleChild = new SampleChild();
1101
+ 23. }
1102
+
1103
+ 25. @Entry
1104
+ 26. @ComponentV2
1105
+ 27. struct Page1 {
1106
+ 28. @Local refresh: number = 0;
1107
+ 29. // 使用key:connect3存储
1108
+ 30. @Local p: Sample = PersistenceV2.connect(Sample, 'connect3', () => new Sample())!;
1109
+
1110
+ 32. build() {
1111
+ 33. Column({ space: 5 }) {
1112
+ 34. // 显示数据
1113
+ 35. Text('Key connect3: ' + this.p.father.childId.toString())
1114
+ 36. .onClick(() => {
1115
+ 37. this.p.father.childId += 1;
1116
+ 38. })
1117
+ 39. .fontSize(25)
1118
+ 40. .fontColor(Color.Red)
1119
+
1120
+ 42. // save接口
1121
+ 43. // 未被@Trace装饰的变量需要借助状态变量refresh才能刷新
1122
+ 44. Text('save key connect3: ' + this.p.father.groupId.toString() + ' refresh:' + this.refresh)
1123
+ 45. .onClick(() => {
1124
+ 46. // 未被@Trace保存的对象无法自动存储,需要调用save存储
1125
+ 47. this.p.father.groupId += 1;
1126
+ 48. PersistenceV2.save('connect3');
1127
+ 49. this.refresh += 1;
1128
+ 50. })
1129
+ 51. .fontSize(25)
1130
+ 52. }
1131
+ 53. .width('100%')
1132
+ 54. }
1133
+ 55. }
1134
+ ```
1135
+
1136
+ [PersistenceV2ConnectMigration1.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ParadigmStateManagement/entry/src/main/ets/pages/persistenceV2/PersistenceV2ConnectMigration1.ets#L16-L72)
1137
+
1138
+ ```
1139
+ 1. // 迁移到globalConnect
1140
+ 2. import { PersistenceV2, Type } from '@kit.ArkUI';
1141
+ 3. import { hilog } from '@kit.PerformanceAnalysisKit';
1142
+
1143
+ 5. const DOMAIN = 0x0000;
1144
+
1145
+ 7. // 接受序列化失败的回调
1146
+ 8. PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
1147
+ 9. hilog.error(DOMAIN, 'testTag', '%{public}s', `error key: ${key}, reason: ${reason}, message: ${msg}`);
1148
+ 10. });
1149
+
1150
+ 12. @ObservedV2
1151
+ 13. class SampleChild {
1152
+ 14. @Trace public childId: number = 0;
1153
+ 15. public groupId: number = 1;
1154
+ 16. }
1155
+
1156
+ 18. @ObservedV2
1157
+ 19. export class Sample {
1158
+ 20. // 对于复杂对象需要@Type修饰,确保序列化成功
1159
+ 21. @Type(SampleChild)
1160
+ 22. @Trace public father: SampleChild = new SampleChild();
1161
+ 23. }
1162
+
1163
+ 25. // 用于判断是否完成数据迁移的辅助数据
1164
+ 26. @ObservedV2
1165
+ 27. class StorageState {
1166
+ 28. @Trace public isCompleteMoving: boolean = false;
1167
+ 29. }
1168
+
1169
+ 31. function move() {
1170
+ 32. let movingState = PersistenceV2.globalConnect({ type: StorageState, defaultCreator: () => new StorageState() })!;
1171
+ 33. if (!movingState.isCompleteMoving) {
1172
+ 34. let p: Sample = PersistenceV2.connect(Sample, 'connect3', () => new Sample())!;
1173
+ 35. PersistenceV2.remove('connect3');
1174
+ 36. let p1 = PersistenceV2.globalConnect({ type: Sample, key: 'connect4', defaultCreator: () => p })!; // 使用默认构造函数也可以
1175
+ 37. // 赋值数据,@Trace修饰的会自动保存
1176
+ 38. p1.father = p.father;
1177
+ 39. // 将迁移标志设置为true
1178
+ 40. movingState.isCompleteMoving = true;
1179
+ 41. }
1180
+ 42. }
1181
+
1182
+ 44. move();
1183
+
1184
+ 46. @Entry
1185
+ 47. @ComponentV2
1186
+ 48. struct Page1 {
1187
+ 49. @Local refresh: number = 0;
1188
+ 50. // 使用key:connect4存入数据
1189
+ 51. @Local p: Sample =
1190
+ 52. PersistenceV2.globalConnect({ type: Sample, key: 'connect4', defaultCreator: () => new Sample() })!;
1191
+
1192
+ 54. build() {
1193
+ 55. Column({ space: 5 }) {
1194
+ 56. // 显示数据
1195
+ 57. Text('Key connect4: ' + this.p.father.childId.toString())
1196
+ 58. .onClick(() => {
1197
+ 59. this.p.father.childId += 1;
1198
+ 60. })
1199
+ 61. .fontSize(25)
1200
+ 62. .fontColor(Color.Red)
1201
+
1202
+ 64. // save接口
1203
+ 65. // 未被@Trace装饰的变量需要借助状态变量refresh才能刷新
1204
+ 66. Text('save key connect4: ' + this.p.father.groupId.toString() + ' refresh:' + this.refresh)
1205
+ 67. .onClick(() => {
1206
+ 68. // 未被@Trace保存的对象无法自动存储,需要调用save存储
1207
+ 69. this.p.father.groupId += 1;
1208
+ 70. PersistenceV2.save('connect4');
1209
+ 71. this.refresh += 1;
1210
+ 72. })
1211
+ 73. .fontSize(25)
1212
+ 74. }
1213
+ 75. .width('100%')
1214
+ 76. }
1215
+ 77. }
1216
+ ```
1217
+
1218
+ [PersistenceV2ConnectMigration2.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ParadigmStateManagement/entry/src/main/ets/pages/persistenceV2/PersistenceV2ConnectMigration2.ets#L16-L94)
1219
+
1220
+ connect向globalConnect迁移,需要将key绑定的value赋值给globalConnect进行存储,之后当自定义组件使用globalConnect连接时,globalConnect绑定的数据即为之前使用connect保存的数据,开发者可以自定义move函数,并将其放在合适位置迁移即可。