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