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
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** 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).
10
11>**NOTE**
12>
13>**PersistenceV2** is supported since API version 12.
14>
15
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> **keyOrDefaultCreater**: 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 third parameter is used when no **key** is specified or the second parameter is invalid. Otherwise, the second parameter is used.
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. If different types of data are connected to the same key, the application exception occurs.
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### remove: Deleting the Stored Data of a Specified Key
58
59```JavaScript
60static remove<T>(keyOrType: string | TypeConstructorWithArgs<T>): void;
61```
62
63| remove       | Description                                                 |
64| ------------ | ----------------------------------------------------- |
65| Parameter        | **keyOrType**: key to be deleted. If the key is of the **type**, the key to be deleted is the name of the **type**.                                         |
66| Return value      | None.|
67
68>**NOTE**
69>
70>If a key that does not exist in **PersistenceV2** is deleted, a warning is reported.
71
72### keys: Returning All Keys Stored in PersistenceV2
73
74```JavaScript
75static keys(): Array<string>;
76```
77
78| keys         | Description                                                 |
79| ------------ | ----------------------------------------------------- |
80| Parameter        | None.                                        |
81| Return value      | All keys in **PersistenceV2**.|
82
83
84### save: Persisting Stored Data Manually
85
86```ts
87static save<T>(keyOrType: string | TypeConstructorWithArgs<T>): void;
88```
89
90| save         | Description                                                 |
91| ------------ | ----------------------------------------------------- |
92| Parameter        | **keyOrType**: key that needs to be manually persist. If the key is of the **Type**, the key is the name of the **Type**.                                         |
93| Return value      | None.|
94
95>**NOTE**
96>
97>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.
98>
99>It is useless to manually persist the keys that are not in the **connect** state in the memory.
100
101
102### **notifyOnError**: Callback for Responding to a Serialization or Deserialization Failure
103
104```ts
105static notifyOnError(callback: PersistenceErrorCallback | undefined): void;
106```
107
108| notifyOnError| Description                                                 |
109| ------------ | ----------------------------------------------------- |
110| Parameter        | **callback**: When a serialization or deserialization fails, the callback is executed. Pass in **undefined** can cancel this callback.|
111| Return value      | None.|
112
113>**NOTE**
114>
115>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.
116
117
118## Constraints
119
1201. This singleton must be used together with the UI thread only. Other threads, for example, @Sendable decorator is not supported.
121
1222. Types such as collections.Set and collections.Map are not supported.
123
1243. Non-buildin types, such as native PixelMap, NativePointer, and ArrayList types, are not supported.
125
1264. A single key supports a maximum of 8 KB data. If the data is too large, the persistence fails.
127
1285. 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.
129
1306. Objects that used for loop reference are not supported.
131
1327. 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.
133
1348. Do not store a large amount of persistent data. Otherwise, frame freezing may occur.
135
136## Use Scenarios
137
138### Storing Data Between Two Pages
139
140Page 1
141```ts
142import { PersistenceV2 } from '@kit.ArkUI';
143import { Sample } from '../Sample';
144
145// Callback used to receive serialization failure.
146PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
147  console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
148});
149
150@Entry
151@ComponentV2
152struct Page1 {
153  // 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.
154  // Add @Local to decorate the prop attribute that needs to change the connected object. (Changing the connected object is not recommended.)
155  @Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;
156  pageStack: NavPathStack = new NavPathStack();
157
158  build() {
159    Navigation(this.pageStack) {
160      Column() {
161        Button('Go to page2')
162          .onClick(() => {
163            this.pageStack.pushPathByName('Page2', null);
164          })
165
166        Button('Page1 connect the key Sample')
167          .onClick(() => {
168            // 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.
169            // Changing the connected object for the prop attribute is not recommended.
170            this.prop = PersistenceV2.connect(Sample, 'Sample', () => new Sample())!;
171          })
172
173        Button('Page1 remove the key Sample')
174          .onClick(() => {
175            // After being deleted from PersistenceV2, prop will no longer be associated with the value whose key is Sample.
176            PersistenceV2.remove(Sample);
177          })
178
179        Button('Page1 save the key Sample')
180          .onClick(() => {
181            // If the sample is in the connect state, persist the KV pair of the Sample.
182            PersistenceV2.save(Sample);
183          })
184
185        Text(`Page1 add 1 to prop.p1: ${this.prop.f.p1}`)
186          .fontSize(30)
187          .onClick(() => {
188            this.prop.f.p1++;
189          })
190
191        Text(`Page1 add 1 to prop.p2: ${this.prop.f.p2}`)
192          .fontSize(30)
193          .onClick(() => {
194            // The page is not re-rendered, but the value of p2 is changed.
195            this.prop.f.p2++;
196          })
197
198        // Obtain all keys in the current PersistenceV2.
199        Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`)
200          .fontSize(30)
201      }
202      }
203  }
204}
205```
206
207Page 2
208```ts
209import { PersistenceV2 } from '@kit.ArkUI';
210import { Sample } from '../Sample';
211
212@Builder
213export function Page2Builder() {
214  Page2()
215}
216
217@ComponentV2
218struct Page2 {
219  // 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.
220  // Add @Local to decorate the prop attribute that needs to change the connected object. (Changing the connected object is not recommended.)
221  @Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;
222  pathStack: NavPathStack = new NavPathStack();
223
224  build() {
225    NavDestination() {
226      Column() {
227        Button('Page2 connect the key Sample1')
228          .onClick(() => {
229            // 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.
230            // Changing the connected object for the prop attribute is not recommended.
231            this.prop = PersistenceV2.connect(Sample, 'Sample1', () => new Sample())!;
232          })
233
234        Text(`Page2 add 1 to prop.p1: ${this.prop.f.p1}`)
235          .fontSize(30)
236          .onClick(() => {
237            this.prop.f.p1++;
238          })
239
240        Text(`Page2 add 1 to prop.p2: ${this.prop.f.p2}`)
241          .fontSize(30)
242          .onClick(() => {
243            // The page is not re-rendered, but the value of p2 is changed, which is performed after re-initialization.
244            this.prop.f.p2++;
245          })
246
247        // Obtain all keys in the current PersistenceV2.
248        Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`)
249          .fontSize(30)
250      }
251    }
252    .onReady((context: NavDestinationContext) => {
253      this.pathStack = context.pathStack;
254    })
255  }
256}
257```
258When 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.
259```json
260{
261  "routerMap": [
262    {
263      "name": "Page2",
264      "pageSourceFile": "src/main/ets/pages/Page2.ets",
265      "buildFunction": "Page2Builder",
266      "data": {
267        "description" : "AppStorageV2 example"
268      }
269    }
270  ]
271}
272```
273
274Data page
275```ts
276import { Type } from '@kit.ArkUI';
277
278// Data center
279@ObservedV2
280class SampleChild {
281  @Trace p1: number = 0;
282  p2: number = 10;
283}
284
285@ObservedV2
286export class Sample {
287  // Complex objects need to be decorated by @Type to ensure successful serialization.
288  @Type(SampleChild)
289  @Trace f: SampleChild = new SampleChild();
290}
291```
292
293