1# PersistenceV2: 持久化储存UI状态 2 3为了增强状态管理框架对持久化存储UI的能力,开发者可以使用PersistenceV2存储持久化的数据。AppStorageV2是运行时内存,但是在应用退出再次启动后,依然能保存选定的结果,是应用开发中十分常见的现象,这就需要用到PersistenceV2。 4 5PersistenceV2是应用程序中的可选单例对象。此对象的作用是持久化存储UI相关的数据,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同。 6 7>**说明:** 8> 9>PersistenceV2从API version 12开始支持。 10> 11>当前状态管理(V2试用版)仍在逐步开发中,相关功能尚未成熟,建议开发者尝鲜试用。 12 13 14## 概述 15 16PersistenceV2是在应用UI启动时会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。数据通过唯一的键字符串值访问。不同于AppStorageV2,PersistenceV2还将最新数据储存在设备磁盘上(持久化)。这意味着,应用退出再次启动后,依然能保存选定的结果。 17 18对于与PersistenceV2关联的[\@ObservedV2](arkts-new-observedV2-and-trace.md)对象,该对象的[\@Trace](arkts-new-observedV2-and-trace.md)属性的变化,会触发**整个关联对象的自动持久化**;非[\@Trace](arkts-new-observedV2-and-trace.md)属性的变化则不会,如有必要,可调用PersistenceV2 API手动持久化。 19 20PersistenceV2可以和UI组件同步,且可以在应用业务逻辑中被访问。 21 22PersistenceV2支持应用的[主线程](../application-models/thread-model-stage.md)内多个UIAbility实例间的状态共享。 23 24 25## 使用说明 26 27### connect:创建或获取储存的数据 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 | 说明 | 38| ------------ | ----------------------------------------------------- | 39| 参数 | type:指定的类型,若未指定key,则使用type的name作为key;</br > keyOrDefaultCreater:指定的key,或者是默认数据的构造器;</br > defaultCreator:默认数据的构造器。 | 40| 返回值 | 创建或获取数据成功时,返回数据;否则返回undefined。 | 41 42>**说明:** 43> 44>1、若未指定key,使用第二个参数作为默认构造器;否则使用第三个参数作为默认构造器(第二个参数非法也使用第三个参数作为默认构造器); 45> 46>2、确保数据已经存储在PersistenceV2中,可省略默认构造器,获取存储的数据;否则必须指定默认构造器,不指定将导致应用异常; 47> 48>3、同一个key,connect不同类型的数据会导致应用异常,应用需要确保类型匹配; 49> 50>4、key建议使用有意义的值,可由字母、数字、下划线组成,长度不超过255,使用非法字符或空字符的行为是未定义的; 51> 52>5、关联[\@Observed](arkts-observed-and-objectlink.md)对象时,由于该类型的name属性未定义,需要指定key或者自定义name属性。 53 54### remove:删除指定key的储存数据 55 56```JavaScript 57static remove<T>(keyOrType: string | TypeConstructorWithArgs<T>): void; 58``` 59 60| remove | 说明 | 61| ------------ | ----------------------------------------------------- | 62| 参数 | keyOrType:需要删除的key;如果指定的是type类型,删除的key为type的name。 | 63| 返回值 | 无。 | 64 65>**说明:** 66> 67>删除PersistenceV2中不存在的key会报警告。 68 69### keys:返回所有PersistenceV2中的key 70 71```JavaScript 72static keys(): Array<string>; 73``` 74 75| keys | 说明 | 76| ------------ | ----------------------------------------------------- | 77| 参数 | 无。 | 78| 返回值 | 所有PersistenceV2中的key。 | 79 80 81### save:手动持久化数据 82 83```JavaScript 84static save<T>(keyOrType: string | TypeConstructorWithArgs<T>): void; 85``` 86 87| save | 说明 | 88| ------------ | ----------------------------------------------------- | 89| 参数 | keyOrType:需要手动持久化的key;如果指定的是type类型,key为type的name。 | 90| 返回值 | 无。 | 91 92>**说明:** 93> 94>由于非[\@Trace](arkts-new-observedV2-and-trace.md)的数据改变不会触发PersistenceV2的自动持久化,如有必要,可调用该接口持久化对应key的数据; 95> 96>手动持久化当前内存中不处于connect状态的key是无意义的。 97 98 99### notifyOnError:响应序列化或反序列化失败的回调 100 101```JavaScript 102static notifyOnError(callback: PersistenceErrorCallback | undefined): void; 103``` 104 105| notifyOnError| 说明 | 106| ------------ | ----------------------------------------------------- | 107| 参数 | callback:当序列化或者反序列化失败时,执行该回调;若传入undefined,取消该回调。| 108| 返回值 | 无。 | 109 110>**说明:** 111> 112>将数据存入磁盘时,需要对数据进行序列化;当某个key序列化失败时,错误是不可预知的;可调用该接口捕获异常。 113 114 115## 使用限制 116 1171、需要配合UI使用(UI线程),不能在其他线程使用,如不支持@Sendable; 118 1192、不支持collections.Set、collections.Map等类型; 120 1213、不支持非buildin类型,如PixelMap、NativePointer、ArrayList等Native类型; 122 1234、单个key支持数据大小约8k,过大会导致持久化失败; 124 1255、持久化的数据必须是class对象,不能是容器(如Array、Set、Map),不能是buildin的构造对象(如Date、Number); 126 1276、不支持循环引用的对象; 128 1297、只有[\@Trace](arkts-new-observedV2-and-trace.md)的数据改变会触发自动持久化,如V1状态变量、[\@Observed](arkts-observed-and-objectlink.md)对象、普通数据的改变不会触发持久化; 130 1318、不宜大量持久化数据,可能会导致页面卡顿。 132 133## 使用场景 134 135### 在两个页面之间存储数据 136 137页面1 138```ts 139import { router, PersistenceV2 } from '@kit.ArkUI'; 140import { Sample } from '../Sample'; 141 142// 接受序列化失败的回调 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 // 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联 151 // 对于需要换connect对象的prop属性,需要加@Local修饰(不建议对属性换connect的对象) 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 // 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联 166 // 不建议对prop属性换connect的对象 167 this.prop = PersistenceV2.connect(Sample, 'Sample', () => new Sample())!; 168 }) 169 170 Button('Page1 remove the key Sample') 171 .onClick(() => { 172 // 从PersistenceV2中删除后,prop将不会再与key为Sample的值关联 173 PersistenceV2.remove(Sample); 174 }) 175 176 Button('Page1 save the key Sample') 177 .onClick(() => { 178 // 如果处于connect状态,持久化key为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 // 页面不刷新,但是p2的值改变了 192 this.prop.f.p2++; 193 }) 194 195 // 获取当前PersistenceV2里面的所有key 196 Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`) 197 .fontSize(30) 198 } 199 } 200} 201``` 202 203页面2 204```ts 205import { PersistenceV2 } from '@kit.ArkUI'; 206import { Sample } from '../Sample'; 207 208@Entry 209@ComponentV2 210struct Page2 { 211 // 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联 212 // 对于需要换connect对象的prop属性,需要加@Local修饰(不建议对属性换connect的对象) 213 @Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!; 214 215 build() { 216 Column() { 217 Button('Page2 connect the key Sample1') 218 .onClick(() => { 219 // 在PersistenceV2中创建一个key为Sample1的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联 220 // 不建议对prop属性换connect的对象 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 // 页面不刷新,但是p2的值改变了;只有重新初始化才会改变 234 this.prop.f.p2++; 235 }) 236 237 // 获取当前PersistenceV2里面的所有key 238 Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`) 239 .fontSize(30) 240 } 241 } 242} 243``` 244 245数据页面 246```ts 247import { Type } from '@kit.ArkUI'; 248 249// 数据中心 250@ObservedV2 251class SampleChild { 252 @Trace p1: number = 0; 253 p2: number = 10; 254} 255 256@ObservedV2 257export class Sample { 258 // 对于复杂对象需要@Type修饰,确保序列化成功 259 @Type(SampleChild) 260 @Trace f: SampleChild = new SampleChild(); 261} 262``` 263 264