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