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. During application development, you may want selected attributes to persist even when the application is closed. In this case, you'll need PersistenceV2.
4
5PersistenceV2 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>**NOTE**
8>
9>PersistenceV2 is supported since API version 12.
10>
11>State management V2 is still under development, and some features may be incomplete or not always work as expected.
12
13
14## Overview
15
16PersistenceV2 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.
17
18For 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.
19
20UI components synchronize application state attributes with PersistenceV2. PersistenceV2 can be accessed during implementation of application service logic as well.
21
22PersistenceV2 supports state sharing among multiple UIAbility instances in the [main thread](../application-models/thread-model-stage.md) of an application.
23
24
25## How to Use
26
27### connect: Creating or Obtaining Stored Data
28
29```JavaScript
30static connect<T extends object>(
31    type: TypeConstructorWithArgs<T>,
32    keyOrDefaultCreator?: string | StorageDefaultCreator<T>,
33    defaultCreator?: StorageDefaultCreator<T> 
34): T | undefined;
35```
36
37| connect      | Description                                                 |
38| ------------ | ----------------------------------------------------- |
39| Parameter        | **type**: specified type. If no **key** is specified, the name of the **type** is used as the **key**.<br> **keyOrDefaultCreater**: specified key or default constructor.<br> **defaultCreator**: default constructor.                                         |
40| Return value      | After creating or obtaining data, value is returned. Otherwise, **undefined** is returned. |
41
42>**NOTE**
43>
44>1. The third parameter is used when no **key** is specified or the second parameter is invalid. Otherwise, the second parameter is used.
45>
46>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.
47>
48>3. Ensure that the data types match the key. If different types of data are connected to the same key, the application exception occurs.
49>
50>4. You are advised to use meaningful values for keys. The values can contain letters, digits, and underscores (_) and a maximum of 255 characters. If use invalid characters or null characters, undefined behavior may occur.
51>
52>5. When match the key with the [\@Observed](arkts-observed-and-objectlink.md) object, specify the key or customize the **name** attribute.
53
54### remove: Deleting the Stored Data of a Specified Key
55
56```JavaScript
57static remove<T>(keyOrType: string | TypeConstructorWithArgs<T>): void;
58```
59
60| remove       | Description                                                 |
61| ------------ | ----------------------------------------------------- |
62| Parameter        | **keyOrType**: key to be deleted. If the key is of the **type**, the key to be deleted is the name of the **type**.                                         |
63| Return value      | None. |
64
65>**NOTE**
66>
67>If a key that does not exist in PersistenceV2 is deleted, a warning is reported.
68
69### keys: Returning All Keys Stored in PersistenceV2
70
71```JavaScript
72static keys(): Array<string>;
73```
74
75| keys         | Description                                                 |
76| ------------ | ----------------------------------------------------- |
77| Parameter        | None.                                        |
78| Return value      | All keys in PersistenceV2. |
79
80
81### save: Persisting Stored Data Manually
82
83```JavaScript
84static save<T>(keyOrType: string | TypeConstructorWithArgs<T>): void;
85```
86
87| save         | Description                                                 |
88| ------------ | ----------------------------------------------------- |
89| Parameter        | **keyOrType**: key that needs to be manually persist. If the key is of the **Type**, the key is the name of the **Type**.                                         |
90| Return value      | None. |
91
92>**NOTE**
93>
94>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.
95>
96>It is useless to manually persist the keys that are not in the **connect** state in the memory.
97
98
99### **notifyOnError**: Callback for Responding to a Serialization or Deserialization Failure
100
101```JavaScript
102static notifyOnError(callback: PersistenceErrorCallback | undefined): void;
103```
104
105| notifyOnError| Description                                                 |
106| ------------ | ----------------------------------------------------- |
107| Parameter        | **callback**: When a serialization or deserialization fails, the callback is executed. Pass in **undefined** can cancel this callback.|
108| Return value      | None. |
109
110>**NOTE**
111>
112>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.
113
114
115## Constraints
116
1171. This singleton must be used together with the UI thread only. Other threads, for example, @Sendable decorator is not supported.
118
1192. Types such as collections.Set and collections.Map are not supported.
120
1213. Non-buildin types, such as native PixelMap, NativePointer, and ArrayList types, are not supported.
122
1234. A single key supports a maximum of 8 KB data. If the data is too large, the persistence fails.
124
1255. The persistent data must be a class object. Containers, such as Array, Set, and Map, or objects of the builtin types, such as Date and Number, are not supported.
126
1276. Objects that used for loop reference are not supported.
128
1297. 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.
130
1318. Do not store a large amount of persistent data. Otherwise, frame freezing may occur.
132
133## Use Scenarios
134
135### Storing Data Between Two Pages
136
137Page 1
138```ts
139import { router, PersistenceV2 } from '@kit.ArkUI';
140import { Sample } from '../Sample';
141
142// Receive the callback for serialization failure.
143PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
144  console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
145});
146
147@Entry
148@ComponentV2
149struct Page1 {
150  // 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.
151  // Add @Local to decorate the prop attribute that needs to change the connected object. (Changing the connected object is not recommended.)
152  @Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;
153
154  build() {
155    Column() {
156      Button('Go to page2')
157        .onClick(() => {
158          router.pushUrl({
159            url: 'pages/Page2'
160          })
161        })
162
163      Button('Page1 connect the key Sample')
164        .onClick(() => {
165          // 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.
166          // Changing the connected object for the prop attribute is not recommended.
167          this.prop = PersistenceV2.connect(Sample, 'Sample', () => new Sample())!;
168        })
169
170      Button('Page1 remove the key Sample')
171        .onClick(() => {
172          // After being deleted from PersistenceV2, prop will no longer be associated with the value whose key is Sample.
173          PersistenceV2.remove(Sample);
174        })
175
176      Button('Page1 save the key Sample')
177        .onClick(() => {
178          // If the sample is in the connect state, persist the KV pair of the Sample.
179          PersistenceV2.save(Sample);
180        })
181
182      Text(`Page1 add 1 to prop.p1: ${this.prop.f.p1}`)
183        .fontSize(30)
184        .onClick(() => {
185          this.prop.f.p1++;
186        })
187
188      Text(`Page1 add 1 to prop.p2: ${this.prop.f.p2}`)
189        .fontSize(30)
190        .onClick(() => {
191          // The page is not re-rendered, but the value of p2 is changed.
192          this.prop.f.p2++;
193        })
194
195      // Obtain all keys in the current PersistenceV2.
196      Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`)
197        .fontSize(30)
198    }
199  }
200}
201```
202
203Page 2
204```ts
205import { PersistenceV2 } from '@kit.ArkUI';
206import { Sample } from '../Sample';
207
208@Entry
209@ComponentV2
210struct Page2 {
211  // 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.
212  // Add @Local to decorate the prop attribute that needs to change the connected object. (Changing the connected object is not recommended.)
213  @Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;
214
215  build() {
216    Column() {
217      Button('Page2 connect the key Sample1')
218        .onClick(() => {
219          // 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.
220          // Changing the connected object for the prop attribute is not recommended.
221          this.prop = PersistenceV2.connect(Sample, 'Sample1', () => new Sample())!;
222        })
223
224      Text(`Page2 add 1 to prop.p1: ${this.prop.f.p1}`)
225        .fontSize(30)
226        .onClick(() => {
227          this.prop.f.p1++;
228        })
229
230      Text(`Page2 add 1 to prop.p2: ${this.prop.f.p2}`)
231        .fontSize(30)
232        .onClick(() => {
233          // The page is not re-rendered, but the value of p2 is changed, which is performed after re-initialization.
234          this.prop.f.p2++;
235        })
236
237      // Obtain all keys in the current PersistenceV2.
238      Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`)
239        .fontSize(30)
240    }
241  }
242}
243```
244
245Data page
246```ts
247import { Type } from '@kit.ArkUI';
248
249// Data center
250@ObservedV2
251class SampleChild {
252  @Trace p1: number = 0;
253  p2: number = 10;
254}
255
256@ObservedV2
257export class Sample {
258  // Complex objects need to be decorated by @Type to ensure successful serialization.
259  @Type(SampleChild)
260  @Trace f: SampleChild = new SampleChild();
261}
262```
263