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