• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# PersistenceV2: Persisting Application State
2
3To enhance the state management framework's capability of persistently storing UIs, you can use **PersistenceV2** to persist data.
4
5**PersistenceV2** is an optional singleton object within an application. Its purpose is to persist UI-related data so that their values are the same upon application re-start as they were when the application was closed.
6
7**PersistenceV2** provides the state variable persistence capability. You can bind the same key through **connect** or **globalConnect** to implement the persistence capability during state variable change and application cold start.
8
9Before reading this topic, you are advised to read [\@ComponentV2](./arkts-new-componentV2.md), [\@ObservedV2 and \@Trace](./arkts-new-observedV2-and-trace.md), and API reference of [PersistentV2](../../reference/apis-arkui/js-apis-StateManagement.md#persistencev2).
10
11>**NOTE**
12>
13>**PersistenceV2** is supported since API version 12.
14>
15>**globalConnect** is supported since API version 18. The behavior of **globalConnect** is the same as that of **connect**. The only difference is that the underlying storage path of **connect** is a module-level path, while that of **globalConnect** is an application-level path. For details, see the section [Using connect and globalConnect in Different Modules](#using-connect-and-globalconnect-in-different-modules).
16
17
18## Overview
19
20**PersistenceV2** is a singleton to be created when the application UI is started. Its purpose is to provide central storage for application UI state attributes. Each attribute is accessed using a unique key, which is a string. Unlike **AppStorageV2**, **PersistenceV2** also persistently stores the latest data on device disks. In this way, the selected result can still be saved even when the application is closed.
21
22For a [\@ObservedV2](./arkts-new-observedV2-and-trace.md) object associated with **PersistenceV2**, the change of the [\@Trace](./arkts-new-observedV2-and-trace.md) attribute of the object triggers automatic persistence of the entire associated object. If necessary, you can call **PersistenceV2** APIs to manually perform persistence.
23
24**PersistenceV2** can synchronize application state attributes with UI components and can be accessed during implementation of application service logic as well.
25
26**PersistenceV2** supports state sharing among multiple UIAbility instances in the [main thread](../../application-models/thread-model-stage.md) of an application.
27
28## How to Use
29
30### connect: Creating or Obtaining Stored Data
31
32```JavaScript
33static connect<T extends object>(
34    type: TypeConstructorWithArgs<T>,
35    keyOrDefaultCreator?: string | StorageDefaultCreator<T>,
36    defaultCreator?: StorageDefaultCreator<T>
37): T | undefined;
38```
39
40| connect      | Description                                                 |
41| ------------ | ----------------------------------------------------- |
42| Parameter        | **type**: specified type. If no **key** is specified, the name of the **type** is used as the **key**.<br> **keyOrDefaultCreator**: specified key or default constructor.<br> **defaultCreator**: default constructor.                                         |
43| Return value      | After creating or obtaining data, value is returned. Otherwise, **undefined** is returned.|
44
45>**NOTE**
46>
47>1. The second parameter is used when no **key** is specified or the second parameter is invalid, and the third parameter is used in all other cases.
48>
49>2. If the data has been stored in **PersistenceV2**, you can obtain the stored data without using the default constructor. Otherwise, you must specify the default constructor. If no constructor is specified, the application exception occurs.
50>
51>3. Ensure that the data types match the key. Connecting different types of data to the same key will result in an application exception.
52>
53>4. You are advised to use meaningful values for keys. The values can contain letters, digits, and underscores (_) and a maximum of 255 characters. Using invalid characters or null characters will result in undefined behavior.
54>
55>5. When matching the key with the [\@Observed](./arkts-observed-and-objectlink.md) object, specify the key or customize the **name** attribute.
56>
57>6. The data storage path is at the module level. That is, the data copy is stored in the persistent file of the corresponding module when the module calls the **connect** function. If multiple modules use the same key, the data of the module that uses the **connect** function first is used, and the data in **PersistenceV2** is also stored in the module that uses the **connect** function first.
58>
59>7. The storage path, determined when the first ability of the application is started, is the module to which the ability belongs. If an ability calls the **connect** function and can be started by different modules, the number of data copies is the same as the number of startup modes of the ability.
60
61### globalConnect: Creating or Obtaining Stored Data
62
63```ts
64// globalConnect API
65static globalConnect<T extends object>(
66    type: ConnectOptions<T>
67  ): T | undefined;
68```
69
70```ts
71// ConnectOptions parameters
72class ConnectOptions<T extends object> {
73  type: TypeConstructorWithArgs<T>;	// (Mandatory) Specified type.
74  key?: string;	// (Optional) Input key. If no key is specified, the name of the type is used as the key.
75  defaultCreator?: StorageDefaultCreator<T> // Default constructor. You are advised to set this parameter.
76  areaMode?: contextConstant.AreaMode; // (Optional) Encryption parameter.
77}
78```
79
80| globalConnect | Description                                                     |
81| ------------- | --------------------------------------------------------- |
82| Parameter         | type: input parameter of **connect**. For details, see the description of **ConnectOptions**.|
83| Return value       | After creating or obtaining data, value is returned. Otherwise, **undefined** is returned.      |
84
85| ConnectOptions| Description                                                        |
86| :----------------: | :----------------------------------------------------------- |
87|        type        | **TypeConstructorWithArgs\<T\>**: (mandatory) specified type.        |
88|        key         | Input key of the string type. If no value is passed in, the type name is used as the key.            |
89|   defaultCreator   | **StorageDefaultCreator\<T\>**: default constructor. It is recommended that this parameter be passed in. If **globalConnect** is connected to the key for the first time, an error is reported if no parameter is passed in.|
90|      areaMode      | **contextConstant.AreaMode**: encryption level, ranging from EL1 to EL5 (corresponding to the value from 0 to 4). For details, see [Encryption Levels](../../application-models/application-context-stage.md#obtaining-and-modifying-encryption-levels). If no value is passed in, EL2 is used by default. Storage paths vary based on the encryption levels. If the input value of encryption level is not in the range of **0** to **4**, a crash occurs.|
91
92> **NOTE**
93>
94> 1. The second parameter is used when no **key** is specified or the second parameter is invalid, and the third parameter is used in all other cases.
95>
96> 2. If the data has been stored in **PersistenceV2**, you can obtain the stored data without using the default constructor. Otherwise, you must specify the default constructor. If no constructor is specified, the application exception occurs.
97>
98> 3. Ensure that the data types match the key. Matching different types of **globalConnect** data to the same key will result in an application exception.
99>
100> 4. You are advised to use meaningful values for keys. The values can contain letters, digits, and underscores (_) and a maximum of 255 characters. Using invalid characters or null characters will result in undefined behavior.
101>
102> 5. When matching the key with the [\@Observed](./arkts-observed-and-objectlink.md) object, specify the key or customize the **name** attribute.
103>
104> 6. Data is stored in an application-level path. Different modules use the same key and encryption level for **globalConnect**. Only one copy of data is stored.
105>
106> 7. **globalConnect** uses the same key but sets different encryption levels, in which the first-set encryption level is used. Data in **PersistenceV2** is also stored at the encryption level that uses the key first.
107>
108> 8. You are not advised to use **connect** and **globalConnect** together because the data copy paths are different. If they are used together, the keys must be different; otherwise, a crash occurs.
109>
110> 9. To make EL5 encryption level take effect, you need to configure the **ohos.permission.PROTECT_SCREEN_LOCK_DATA** field in the **module.json** file. For details, see [Declaring Permissions](../../security/AccessToken/declare-permissions.md).
111
112### remove: Deleting the Stored Data of a Specified Key
113
114```ts
115static remove<T>(keyOrType: string | TypeConstructorWithArgs<T>): void;
116```
117
118| remove       | Description                                                 |
119| ------------ | ----------------------------------------------------- |
120| Parameter        | **keyOrType**: key to be deleted. If the key is of the **type**, the key to be deleted is the name of the **type**.                                         |
121| Return value      | None.|
122
123>**NOTE**
124>
125>If a key that does not exist in **PersistenceV2** is deleted, a warning is reported.
126
127### keys: Returning All Keys Stored in PersistenceV2
128
129```ts
130static keys(): Array<string>;
131```
132
133| keys         | Description                                                 |
134| ------------ | ----------------------------------------------------- |
135| Parameter        | None.                                        |
136| Return value      | All keys in **PersistenceV2**.|
137
138> **NOTE**
139>
140> All keys in the module-level and application-level storage paths are returned.
141
142### save: Persisting Stored Data Manually
143
144```ts
145static save<T>(keyOrType: string | TypeConstructorWithArgs<T>): void;
146```
147
148| save         | Description                                                 |
149| ------------ | ----------------------------------------------------- |
150| Parameter        | **keyOrType**: key that needs to be manually persist. If the key is of the **Type**, the key is the name of the **Type**.                                         |
151| Return value      | None.|
152
153>**NOTE**
154>
155>Changes to the non-[\@Trace](./arkts-new-observedV2-and-trace.md) data do not trigger **PersistenceV2**. If necessary, call this API to persist the data of the corresponding key.
156>
157>It is useless to manually persist the keys that are not in the **connect** state in the memory.
158
159
160### **notifyOnError**: Callback for Responding to a Serialization or Deserialization Failure
161
162```ts
163static notifyOnError(callback: PersistenceErrorCallback | undefined): void;
164```
165
166| notifyOnError| Description                                                 |
167| ------------ | ----------------------------------------------------- |
168| Parameter        | **callback**: When a serialization or deserialization fails, the callback is executed. Pass in **undefined** can cancel this callback.|
169| Return value      | None.|
170
171>**NOTE**
172>
173>When data is stored to disks, the data needs to be serialized. If a key fails to be serialized, the error is unpredictable. As a result, this API can be called to capture exceptions.
174
175
176## Constraints
177
1781. This singleton must be used together with the UI thread only. Other threads, for example, @Sendable decorator is not supported.
179
1802. Types such as **collections.Set** and **collections.Map** are not supported.
181
1823. Non-buildin types, such as native PixelMap, NativePointer, and ArrayList types, are not supported.
183
1844. A single key supports a maximum of 8 KB data. If the data is too large, the persistence fails.
185
1865. The persistent data must be a class object. Containers, such as Array, Set, and Map, or objects of the built-in types, such as Date and Number, are not supported.
187
1886. Objects that used for loop reference are not supported.
189
1907. Automatic persistency is triggered only when [\@Trace](./arkts-new-observedV2-and-trace.md) data is changed. The change of state variables in V1, [\@Observed](./arkts-observed-and-objectlink.md) objects, and common data does not trigger persistency.
191
1928. Do not store a large amount of persistent data. Otherwise, frame freezing may occur.
193
1949. Do not use **connect** and **globalConnect** together. If you have to, their keys must be different; otherwise, a crash occurs.
195
196## Use Scenarios
197
198### Storing Data Between Two Pages
199
200Data page
201```ts
202// Sample.ets
203import { Type } from '@kit.ArkUI';
204
205// Data center
206@ObservedV2
207class SampleChild {
208  @Trace p1: number = 0;
209  p2: number = 10;
210}
211
212@ObservedV2
213export class Sample {
214  // Complex objects need to be decorated by @Type to ensure successful serialization.
215  @Type(SampleChild)
216  @Trace f: SampleChild = new SampleChild();
217}
218```
219
220Page 1
221```ts
222// Page1.ets
223import { PersistenceV2 } from '@kit.ArkUI';
224import { Sample } from '../Sample';
225
226// Callback used to receive serialization failure.
227PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
228  console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
229});
230
231@Entry
232@ComponentV2
233struct Page1 {
234  // Create a KV pair whose key is Sample in PersistenceV2 (if the key exists, the data in PersistenceV2 is returned) and associate it with prop.
235  // Add @Local to decorate the prop attribute that needs to change the connected object. (Changing the connected object is not recommended.)
236  @Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;
237  pageStack: NavPathStack = new NavPathStack();
238
239  build() {
240    Navigation(this.pageStack) {
241      Column() {
242        Button('Go to page2')
243          .onClick(() => {
244            this.pageStack.pushPathByName('Page2', null);
245          })
246
247        Button('Page1 connect the key Sample')
248          .onClick(() => {
249            // Create a KV pair whose key is Sample in PersistenceV2 (if the key exists, the data in PersistenceV2 is returned) and associate it with prop.
250            // Changing the connected object for the prop attribute is not recommended.
251            this.prop = PersistenceV2.connect(Sample, 'Sample', () => new Sample())!;
252          })
253
254        Button('Page1 remove the key Sample')
255          .onClick(() => {
256            // After being deleted from PersistenceV2, prop will no longer be associated with the value whose key is Sample.
257            PersistenceV2.remove(Sample);
258          })
259
260        Button('Page1 save the key Sample')
261          .onClick(() => {
262            // If the sample is in the connect state, persist the KV pair of the Sample.
263            PersistenceV2.save(Sample);
264          })
265
266        Text(`Page1 add 1 to prop.p1: ${this.prop.f.p1}`)
267          .fontSize(30)
268          .onClick(() => {
269            this.prop.f.p1++;
270          })
271
272        Text(`Page1 add 1 to prop.p2: ${this.prop.f.p2}`)
273          .fontSize(30)
274          .onClick(() => {
275            // The page is not re-rendered, but the value of p2 is changed.
276            this.prop.f.p2++;
277          })
278
279        // Obtain all keys in the current PersistenceV2.
280        Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`)
281          .fontSize(30)
282      }
283      }
284  }
285}
286```
287
288Page 2
289```ts
290// Page2.ets
291import { PersistenceV2 } from '@kit.ArkUI';
292import { Sample } from '../Sample';
293
294@Builder
295export function Page2Builder() {
296  Page2()
297}
298
299@ComponentV2
300struct Page2 {
301  // Create a KV pair whose key is Sample in PersistenceV2 (if the key exists, the data in PersistenceV2 is returned) and associate it with prop.
302  // Add @Local to decorate the prop attribute that needs to change the connected object. (Changing the connected object is not recommended.)
303  @Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;
304  pathStack: NavPathStack = new NavPathStack();
305
306  build() {
307    NavDestination() {
308      Column() {
309        Button('Page2 connect the key Sample1')
310          .onClick(() => {
311            // Create a KV pair whose key is Sample1 in PersistenceV2 (if the key exists, the data in PersistenceV2 is returned) and associate it with prop.
312            // Changing the connected object for the prop attribute is not recommended.
313            this.prop = PersistenceV2.connect(Sample, 'Sample1', () => new Sample())!;
314          })
315
316        Text(`Page2 add 1 to prop.p1: ${this.prop.f.p1}`)
317          .fontSize(30)
318          .onClick(() => {
319            this.prop.f.p1++;
320          })
321
322        Text(`Page2 add 1 to prop.p2: ${this.prop.f.p2}`)
323          .fontSize(30)
324          .onClick(() => {
325            // The page is not re-rendered, but the value of p2 is changed, which is performed after re-initialization.
326            this.prop.f.p2++;
327          })
328
329        // Obtain all keys in the current PersistenceV2.
330        Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`)
331          .fontSize(30)
332      }
333    }
334    .onReady((context: NavDestinationContext) => {
335      this.pathStack = context.pathStack;
336    })
337  }
338}
339```
340When using **Navigation**, you need to add the **route_map.json** file to the **src/main/resources/base/profile** directory, replace the value of **pageSourceFile** with the path of **Page2**, and add **"routerMap": "$profile: route_map"** to the **module.json5** file.
341```json
342{
343  "routerMap": [
344    {
345      "name": "Page2",
346      "pageSourceFile": "src/main/ets/pages/Page2.ets",
347      "buildFunction": "Page2Builder",
348      "data": {
349        "description" : "PersistenceV2 example"
350      }
351    }
352  ]
353}
354```
355
356### Using globalConnect to Store Data
357
358```ts
359import { PersistenceV2, Type, ConnectOptions } from '@kit.ArkUI';
360import { contextConstant } from '@kit.AbilityKit';
361
362// Callback used to receive serialization failure.
363PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
364  console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
365});
366
367@ObservedV2
368class SampleChild {
369  @Trace childId: number = 0;
370  groupId: number = 1;
371}
372
373@ObservedV2
374export class Sample {
375  // Complex objects need to be decorated by @Type to ensure successful serialization.
376  @Type(SampleChild)
377  @Trace father: SampleChild = new SampleChild();
378}
379
380@Entry
381@ComponentV2
382struct Page1 {
383  @Local refresh: number = 0;
384  // Use the type name as the key if no key is passed in; use EL2 as the default encryption level if no encryption parameter is passed in.
385  @Local p: Sample = PersistenceV2.globalConnect({type: Sample, defaultCreator:() => new Sample()})!;
386
387  // Use key:global1 for connection and set the encryption level to EL1.
388  @Local p1: Sample = PersistenceV2.globalConnect({type: Sample, key:'global1', defaultCreator:() => new Sample(), areaMode: contextConstant.AreaMode.EL1})!;
389
390  // Use key:global2 for connection and use the constructor function. If no encryption parameter is passed in, EL2 is used by default.
391  options: ConnectOptions<Sample> = {type: Sample, key: 'global2', defaultCreator:() => new Sample()};
392  @Local p2: Sample = PersistenceV2.globalConnect(this.options)!;
393
394  // Use key:global3 for connection and set the encryption parameter ranging from 0 to 4; otherwise, a crash occurs. In this case, EL3 is set.
395  @Local p3: Sample = PersistenceV2.globalConnect({type: Sample, key:'global3', defaultCreator:() => new Sample(), areaMode: 3})!;
396
397  build() {
398    Column() {
399      /**************************** Display data **************************/
400      // Data decorated by @Trace can be automatically persisted to disks.
401      Text('Key Sample: ' + this.p.father.childId.toString())
402        .onClick(()=> {
403          this.p.father.childId += 1;
404        })
405        .fontSize(25)
406        .fontColor(Color.Red)
407      Text('Key global1: ' + this.p1.father.childId.toString())
408        .onClick(()=> {
409          this.p1.father.childId += 1;
410        })
411        .fontSize(25)
412        .fontColor(Color.Red)
413      Text('Key global2: ' + this.p2.father.childId.toString())
414        .onClick(()=> {
415          this.p2.father.childId += 1;
416        })
417        .fontSize(25)
418        .fontColor(Color.Red)
419      Text('Key global3: ' + this.p3.father.childId.toString())
420        .onClick(()=> {
421          this.p3.father.childId += 1;
422        })
423        .fontSize(25)
424        .fontColor(Color.Red)
425      /**************************** The keys API **************************/
426      // keys() is not updated by itself. You need to use the state variable to update it.
427      Text('Persist keys: ' + PersistenceV2.keys().toString() + ' refresh: ' + this.refresh)
428        .onClick(() => {
429          this.refresh += 1;
430        })
431        .fontSize(25)
432
433      /**************************** The remove API **************************/
434      Text('Remove key Sample: ' + 'refresh: ' + this.refresh)
435        .onClick(() => {
436          // Removing this key will disconnect from PersistenceV2. After that, PersistenceV2 cannot store data even if it is reconnected.
437          PersistenceV2.remove(Sample);
438          this.refresh += 1;
439        })
440        .fontSize(25)
441      Text('Remove key global1: ' + 'refresh: ' + this.refresh)
442        .onClick(() => {
443          // Removing this key will disconnect from PersistenceV2. After that, PersistenceV2 cannot store data even if it is reconnected.
444          PersistenceV2.remove('global1');
445          this.refresh += 1;
446        })
447        .fontSize(25)
448      Text('Remove key global2: ' + 'refresh: ' + this.refresh)
449        .onClick(() => {
450          // Removing this key will disconnect from PersistenceV2. After that, PersistenceV2 cannot store data even if it is reconnected.
451          PersistenceV2.remove('global2');
452          this.refresh += 1;
453        })
454        .fontSize(25)
455      Text('Remove key global3: ' + 'refresh: ' + this.refresh)
456        .onClick(() => {
457          // Removing this key will disconnect from PersistenceV2. After that, PersistenceV2 cannot store data even if it is reconnected.
458          PersistenceV2.remove('global3');
459          this.refresh += 1;
460        })
461        .fontSize(25)
462      /**************************** reConnect **************************/
463      // Fail to connect to the previous state variable after reconnection. Therefore, data cannot be saved.
464      Text('ReConnect key global2: ' + 'refresh: ' + this.refresh)
465        .onClick(() => {
466          // Removing this key will disconnect from PersistenceV2. After that, PersistenceV2 cannot store data even if it is reconnected.
467          PersistenceV2.globalConnect(this.options);
468          this.refresh += 1;
469        })
470        .fontSize(25)
471
472      /**************************** The save API **************************/
473      Text('not save key Sample: ' + this.p.father.groupId.toString() + ' refresh: ' + this.refresh)
474        .onClick(() => {
475          // Objects that are not saved by @Trace cannot be automatically stored.
476          this.p.father.groupId += 1;
477          this.refresh += 1;
478        })
479        .fontSize(25)
480      Text('save key Sample: ' + this.p.father.groupId.toString() + ' refresh: ' + this.refresh)
481        .onClick(() => {
482          // Objects that are not saved by @Trace cannot be automatically stored. You need to call the key for storage.
483          this.p.father.groupId += 1;
484          PersistenceV2.save(Sample);
485          this.refresh += 1;
486        })
487        .fontSize(25)
488    }
489    .width('100%')
490  }
491}
492```
493
494### Using connect and globalConnect in Different Modules
495
496**For the storage path of connect:**
497
4981. **connect** uses the first-started module path as the storage path and data is written back from the memory to this storage path in the disk. If the application is started from another module, the path of the new module is used as the storage path.
499
5002. When different modules use the same key, the key-value pair stored in the module that is started first is written back to the corresponding module.
501
502**For the storage path of GlobalConnect:**
503
504Although **globalConnect** is an application-level path, different encryption levels can be set, indicating different storage paths. **connect** does not support the setting of the encryption level. However, when the encryption level of the module is switched, the module storage path is also switched to the path of the corresponding encryption level.
505
506Create a module based on the project and redirect to the new module based on the sample code. The sample code is as follows:
507
508```ts
509// Module 1
510import { PersistenceV2, Type } from '@kit.ArkUI';
511import { contextConstant, common, Want } from '@kit.AbilityKit';
512
513// Callback used to receive serialization failure.
514PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
515  console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
516});
517
518@ObservedV2
519class SampleChild {
520  @Trace childId: number = 0;
521  groupId: number = 1;
522}
523
524@ObservedV2
525export class Sample {
526  // Complex objects need to be decorated by @Type to ensure successful serialization.
527  @Type(SampleChild)
528  @Trace father: SampleChild = new SampleChild();
529}
530
531@Entry
532@ComponentV2
533struct Page1 {
534  @Local refresh: number = 0;
535  // Use key:global1 for connection and set the encryption level to EL1.
536  @Local p1: Sample = PersistenceV2.globalConnect({type: Sample, key:'globalConnect1', defaultCreator:() => new Sample()})!;
537
538  // Use key:global2 for connection and use the constructor function. If no encryption parameter is passed in, EL2 is used by default.
539  @Local p2: Sample = PersistenceV2.connect(Sample, 'connect2', () => new Sample())!;
540
541  private context = getContext(this) as common.UIAbilityContext;
542
543  build() {
544    Column() {
545      /**************************** Display data **************************/
546      Text('Key globalConnect1: ' + this.p1.father.childId.toString())
547        .onClick(()=> {
548          this.p1.father.childId += 1;
549        })
550        .fontSize(25)
551        .fontColor(Color.Red)
552      Text('Key connect2: ' + this.p2.father.childId.toString())
553        .onClick(()=> {
554          this.p2.father.childId += 1;
555        })
556        .fontSize(25)
557        .fontColor(Color.Red)
558
559      /**************************** Redirection **************************/
560      Button('Redirect to newModule').onClick(() => { // Used between different modules. You are advised to use globalConnect.
561        let want: Want = {
562          deviceId: '', // If deviceId is empty, the device is the local device.
563          bundleName: 'com.example.myPersistenceV2', // Check it in app.json5.
564          moduleName: 'newModule', // Check this optional value in the module.json5 file of the module to be redirected to.
565          abilityName: 'NewModuleAbility',  // Redirect to the ability to start. You can check the ability name in the ability.ets file of the target module.
566          uri:'src/main/ets/pages/Index'
567        }
568        // context is the UIAbilityContext of the initiator UIAbility.
569        this.context.startAbility(want).then(() => {
570          console.info('start ability success');
571        }).catch((err: Error) => {
572          console.error(`start ability failed. code is ${err.name}, message is ${err.message}`);
573        })
574      })
575    }
576    .width('100%')
577    .borderWidth(3)
578    .borderColor(Color.Blue)
579    .margin({top: 5, bottom: 5})
580  }
581}
582```
583
584```ts
585// Module 2
586import { PersistenceV2, Type } from '@kit.ArkUI';
587import { contextConstant } from '@kit.AbilityKit';
588
589// Callback used to receive serialization failure.
590PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
591  console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
592});
593
594@ObservedV2
595class SampleChild {
596  @Trace childId: number = 0;
597  groupId: number = 1;
598}
599
600@ObservedV2
601export class Sample {
602  // Complex objects need to be decorated by @Type to ensure successful serialization.
603  @Type(SampleChild)
604  @Trace father: SampleChild = new SampleChild();
605}
606
607@Entry
608@ComponentV2
609struct Page1 {
610  @Local a: number = 0;
611  // Use key:global1 for connection and set the encryption level to EL1.
612  @Local p1: Sample = PersistenceV2.globalConnect({type: Sample, key:'globalConnect1', defaultCreator:() => new Sample()})!;
613
614  // Use key:global2 for connection and use the constructor function. If no encryption parameter is passed in, EL2 is used by default.
615  @Local p2: Sample = PersistenceV2.connect(Sample, 'connect2', () => new Sample())!;
616
617  build() {
618    Column() {
619      /**************************** Display data **************************/
620      Text('Key globalConnect1: ' + this.p1.father.childId.toString())
621        .onClick(()=> {
622          this.p1.father.childId += 1;
623        })
624        .fontSize(25)
625        .fontColor(Color.Red)
626      Text('Key connect2: ' + this.p2.father.childId.toString())
627        .onClick(()=> {
628          this.p2.father.childId += 1;
629        })
630        .fontSize(25)
631        .fontColor(Color.Red)
632    }
633    .width('100%')
634  }
635}
636```
637
638When you use different startup modes for newModule, the following symptoms may occur:
639
640*   Start the **newModule** and change the variables bound to **globalConnect1** and **connect2**. For example, change the value of **childId** to **5**.
641* Exit the application, clear the background, start the module entry, and start **newModule** by pressing the redirection key. The value of **globalConnect1** is **5**, and the value of **connect2** remains **1**.
642* **globalConnect** is an application-level storage path. For a key, the entire application has only one storage path for the corresponding encryption level. **connect** is a module-level storage path. Each encryption level has a different storage path according to the startup mode of the module.
643
644## Suggestions
645
646You are advised to use the new API **globalConnect** to create and obtain data. The storage specifications and memory specifications of **globalConnect** are the same for an application, and the encryption level can be set without switching the encryption mode of ability. If your application does not involve multiple modules, using **connect** will not affect your application.
647
648### Migrating from connect to globalConnect
649
650```ts
651// Use connect to store data.
652import { PersistenceV2, Type } from '@kit.ArkUI';
653
654// Callback used to receive serialization failure.
655PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
656  console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
657});
658
659@ObservedV2
660class SampleChild {
661  @Trace childId: number = 0;
662  groupId: number = 1;
663}
664
665@ObservedV2
666export class Sample {
667  // Complex objects need to be decorated by @Type to ensure successful serialization.
668  @Type(SampleChild)
669  @Trace father: SampleChild = new SampleChild();
670}
671
672@Entry
673@ComponentV2
674struct Page1 {
675  @Local refresh: number = 0;
676  // Use key:connect2 to store data.
677  @Local p: Sample = PersistenceV2.connect(Sample, 'connect2', () => new Sample())!;
678
679  build() {
680    Column({space: 5}) {
681      /**************************** Display data **************************/
682      Text('Key connect2: ' + this.p.father.childId.toString())
683        .onClick(() => {
684          this.p.father.childId += 1;
685        })
686        .fontSize(25)
687        .fontColor(Color.Red)
688
689      /**************************** The save API **************************/
690      // Non-state variables can be refreshed only by using the state variable refresh.
691      Text('save key Sample: ' + this.p.father.groupId.toString() + ' refresh:' + this.refresh)
692        .onClick(() => {
693          // Objects that are not saved by @Trace cannot be automatically stored. You need to call the key for storage.
694          this.p.father.groupId += 1;
695          PersistenceV2.save('connect2');
696          this.refresh += 1
697        })
698        .fontSize(25)
699    }
700    .width('100%')
701  }
702}
703```
704
705```ts
706// Migrate to GlobalConnect.
707import { PersistenceV2, Type } from '@kit.ArkUI';
708
709// Callback used to receive serialization failure.
710PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
711  console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
712});
713
714@ObservedV2
715class SampleChild {
716  @Trace childId: number = 0;
717  groupId: number = 1;
718}
719
720@ObservedV2
721export class Sample {
722  // Complex objects need to be decorated by @Type to ensure successful serialization.
723  @Type(SampleChild)
724  @Trace father: SampleChild = new SampleChild();
725}
726
727// Auxiliary data used to determine whether data migration is complete
728@ObservedV2
729class StorageState {
730  @Trace isCompleteMoving: boolean = false;
731}
732
733function move() {
734  let movingState = PersistenceV2.globalConnect({type: StorageState, defaultCreator: () => new StorageState()})!;
735  if (!movingState.isCompleteMoving) {
736    let p: Sample = PersistenceV2.connect(Sample, 'connect2', () => new Sample())!;
737    PersistenceV2.remove('connect2');
738    let p1 = PersistenceV2.globalConnect({type: Sample, key: 'connect2', defaultCreator: () = > p})!; // You can use the default constructor.
739    // For assigned value decorated by @Trace, it is automatically saved.
740    p1.father = p.father;
741    // Set the migration flag to true.
742    movingState.isCompleteMoving = true;
743  }
744}
745
746move();
747
748@Entry
749@ComponentV2
750struct Page1 {
751  @Local refresh: number = 0;
752  // Use key:connect2 to store data.
753  @Local p: Sample = PersistenceV2.globalConnect({type: Sample, key:'connect2', defaultCreator:() => new Sample()})!;
754
755  build() {
756    Column({space: 5}) {
757      /**************************** Display data **************************/
758      Text('Key connect2: ' + this.p.father.childId.toString())
759        .onClick(() => {
760          this.p.father.childId += 1;
761        })
762        .fontSize(25)
763        .fontColor(Color.Red)
764
765      /**************************** The save API **************************/
766      // Non-state variables can be refreshed only by using the state variable refresh.
767      Text('save key connect2: ' + this.p.father.groupId.toString() + ' refresh:' + this.refresh)
768        .onClick(() => {
769          // Objects that are not saved by @Trace cannot be automatically stored. You need to call the key for storage.
770          this.p.father.groupId += 1;
771          PersistenceV2.save('connect2');
772          this.refresh += 1
773        })
774        .fontSize(25)
775    }
776    .width('100%')
777  }
778}
779```
780
781To migrate data from **connect** to **globalConnect**, you should assign the value bound to the key to **globalConnect** for storage. When the custom component uses **globalConnect** for connection, the data bound to **globalConnect** is the data saved using **connect**. You can customize the **move** function and move the data to a proper position.
782