1# AppStorageV2: 应用全局UI状态存储 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @zzq212050299--> 5<!--Designer: @s10021109--> 6<!--Tester: @TerryTsao--> 7<!--Adviser: @zhang_yixin13--> 8 9为了增强状态管理框架对应用全局UI状态变量存储的能力,开发者可以使用AppStorageV2存储应用全局UI状态变量数据。 10 11AppStorageV2是提供状态变量在应用级全局共享的能力,开发者可以通过connect绑定同一个key,进行跨ability的数据共享。 12 13在阅读本文档前,建议提前阅读:[\@ComponentV2](./arkts-new-componentV2.md),[\@ObservedV2和\@Trace](./arkts-new-observedV2-and-trace.md),配合阅读:[AppStorageV2-API文档](../../reference/apis-arkui/js-apis-StateManagement.md#appstoragev2)。 14 15>**说明:** 16> 17>AppStorageV2从API version 12开始支持。 18> 19 20## 概述 21 22AppStorageV2是在应用UI启动时会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。AppStorageV2将在应用运行过程保留其数据。数据通过唯一的键字符串值访问。需要注意的是,AppStorage与AppStorageV2之间的数据互不共享。 23 24AppStorageV2可以修改connect的返回值,实现与UI组件的同步。 25 26AppStorageV2支持应用的[主线程](../../application-models/thread-model-stage.md)内多个UIAbility实例间的状态共享。 27 28## 使用说明 29 30### connect:创建或获取存储的数据 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 | 说明 | 41| ------------ | ----------------------------------------------------- | 42| 参数 | type:指定的类型,若未指定key,则使用type的name作为key;</br>keyOrDefaultCreator:指定的key,或者是默认数据的构造器;</br>defaultCreator:默认数据的构造器。 | 43| 返回值 | 创建或获取数据成功时,返回数据;否则返回undefined。 | 44 45>**说明:** 46> 47>1、若未指定key,使用第二个参数作为默认构造器;否则使用第三个参数作为默认构造器(第二个参数非法也使用第三个参数作为默认构造器)。 48> 49>2、确保数据已经存储在AppStorageV2中,可省略默认构造器,获取存储的数据;否则必须指定默认构造器,不指定将导致应用异常。 50> 51>3、同一个key,connect不同类型的数据会导致应用异常,应用需要确保类型匹配。 52> 53>4、key建议使用有意义的值,可由字母、数字、下划线组成,长度不超过255,使用非法字符或空字符的行为是未定义的。 54> 55>5、关联[\@Observed](arkts-observed-and-objectlink.md)对象时,由于该类型的name属性未定义,需要指定key或者自定义name属性。 56 57### remove:删除指定key的存储数据 58 59```JavaScript 60static remove<T>(keyOrType: string | TypeConstructorWithArgs<T>): void; 61``` 62 63| remove | 说明 | 64| ------------ | ----------------------------------------------------- | 65| 参数 | keyOrType:需要删除的key;如果指定的是type类型,删除的key为type的name。 | 66| 返回值 | 无。 | 67 68>**说明:** 69> 70>删除AppStorageV2中不存在的key会报警告。 71 72### keys:返回所有AppStorageV2中的key 73 74```JavaScript 75static keys(): Array<string>; 76``` 77 78| keys | 说明 | 79| ------------ | ----------------------------------------------------- | 80| 参数 | 无。 | 81| 返回值 | 所有AppStorageV2中的key。 | 82 83 84## 使用限制 85 861、只支持class类型。 87 882、需要配合UI使用(UI线程),不能在其他线程使用,如不支持@Sendable。 89 903、不支持collections.Set、collections.Map等类型。 91 924、不支持非built-in类型,如PixelMap、NativePointer、ArrayList等Native类型。 93 945、不支持存储基本类型,如string、number、boolean等。注意:不支持存储基本类型意味着[connect](#connect创建或获取存储的数据)接口传入的类型不能是基本类型,但connect传入的class中可以包含基本类型。 95 96## 使用场景 97 98### 使用AppStorageV2 99 100AppStorageV2使用connect接口即可实现对AppStorageV2中数据的修改和同步,如果修改的数据被@Trace装饰,该数据的修改会同步更新UI。需要注意的是,使用remove接口只会将数据从AppStorageV2中删除,不影响组件中已创建的数据,详见以下示例代码: 101 102```ts 103import { AppStorageV2 } from '@kit.ArkUI'; 104 105@ObservedV2 106class Message { 107 @Trace userID: number; 108 userName: string; 109 110 constructor(userID?: number, userName?: string) { 111 this.userID = userID ?? 1; 112 this.userName = userName ?? 'Jack'; 113 } 114} 115 116@Entry 117@ComponentV2 118struct Index { 119 // 使用connect在AppStorageV2中创建一个key为Message的对象 120 // 修改connect的返回值即可同步回AppStorageV2 121 @Local message: Message = AppStorageV2.connect<Message>(Message, () => new Message())!; 122 123 build() { 124 Column() { 125 // 修改@Trace装饰的类属性,UI能同步刷新 126 Button(`Index userID: ${this.message.userID}`) 127 .onClick(() => { 128 this.message.userID += 1; 129 }) 130 // 修改非@Trace装饰的类属性,UI不会同步刷新,但修改的类属性已同步回AppStorageV2 131 Button(`Index userName: ${this.message.userName}`) 132 .onClick(() => { 133 this.message.userName += 'suf'; 134 }) 135 // remove key Message, 会从AppStorageV2中删除key为Message的对象 136 // remove之后,修改父组件的userId,子组件能同步变化,因为remove只是从AppStorageV2删除,不会影响组件中已存在的数据 137 Button('remove key: Message') 138 .onClick(() => { 139 AppStorageV2.remove<Message>(Message); 140 }) 141 // connect key Message, 会从AppStorageV2中添加key为Message的对象 142 // remove之后,重新添加,修改父子组件的userID,可以发现数据已经不同步,子组件重新connect之后,数据一致 143 Button('connect key: Message') 144 .onClick(() => { 145 this.message = AppStorageV2.connect<Message>(Message, () => new Message(5, 'Rose'))!; 146 }) 147 Divider() 148 Child() 149 } 150 .width('100%') 151 .height('100%') 152 } 153} 154 155@ComponentV2 156struct Child { 157 // 使用connect在AppStorageV2中取出一个key为Message的对象,已在父组件中创建 158 @Local message: Message = AppStorageV2.connect<Message>(Message, () => new Message())!; 159 @Local name: string = this.message.userName; 160 161 build() { 162 Column() { 163 // 修改@Trace装饰的类属性,UI同步刷新,父组件能感知该变化 164 Button(`Child userID: ${this.message.userID}`) 165 .onClick(() => { 166 this.message.userID += 5; 167 }) 168 // 修改父组件中的userName属性,点击name可以同步父组件的类属性修改 169 Button(`Child name: ${this.name}`) 170 .onClick(() => { 171 this.name = this.message.userName; 172 }) 173 // remove key Message, 会从AppStorageV2中删除key为Message的对象 174 Button('remove key: Message') 175 .onClick(() => { 176 AppStorageV2.remove<Message>(Message); 177 }) 178 // connect key Message, 会从AppStorageV2中添加key为Message的对象 179 Button('connect key: Message') 180 .onClick(() => { 181 this.message = AppStorageV2.connect<Message>(Message, () => new Message(10, 'Lucy'))!; 182 }) 183 } 184 .width('100%') 185 .height('100%') 186 } 187} 188``` 189 190### 在两个页面之间存储数据 191 192数据页面 193```ts 194// 数据中心 195// Sample.ets 196@ObservedV2 197export class Sample { 198 @Trace p1: number = 0; 199 p2: number = 10; 200} 201``` 202 203页面1 204```ts 205// Page1.ets 206import { AppStorageV2 } from '@kit.ArkUI'; 207import { Sample } from '../Sample'; 208 209@Entry 210@ComponentV2 211struct Page1 { 212 // 在AppStorageV2中创建一个key为Sample的键值对(如果存在,则返回AppStorageV2中的数据),并且和prop关联 213 @Local prop: Sample = AppStorageV2.connect(Sample, () => new Sample())!; 214 pageStack: NavPathStack = new NavPathStack(); 215 216 build() { 217 Navigation(this.pageStack) { 218 Column() { 219 Button('Go to page2') 220 .onClick(() => { 221 this.pageStack.pushPathByName('Page2', null); 222 }) 223 224 Button('Page1 connect the key Sample') 225 .onClick(() => { 226 // 在AppStorageV2中创建一个key为Sample的键值对(如果存在,则返回AppStorageV2中的数据),并且和prop关联 227 this.prop = AppStorageV2.connect(Sample, 'Sample', () => new Sample())!; 228 }) 229 230 Button('Page1 remove the key Sample') 231 .onClick(() => { 232 // 从AppStorageV2中删除后,prop将不会再与key为Sample的值关联 233 AppStorageV2.remove(Sample); 234 }) 235 236 Text(`Page1 add 1 to prop.p1: ${this.prop.p1}`) 237 .fontSize(30) 238 .onClick(() => { 239 this.prop.p1++; 240 }) 241 242 Text(`Page1 add 1 to prop.p2: ${this.prop.p2}`) 243 .fontSize(30) 244 .onClick(() => { 245 // 页面不刷新,但是p2的值改变了 246 this.prop.p2++; 247 }) 248 249 // 获取当前AppStorageV2里面的所有key 250 Text(`all keys in AppStorage: ${AppStorageV2.keys()}`) 251 .fontSize(30) 252 } 253 } 254 } 255} 256``` 257 258页面2 259```ts 260// Page2.ets 261import { AppStorageV2 } from '@kit.ArkUI'; 262import { Sample } from '../Sample'; 263 264@Builder 265export function Page2Builder() { 266 Page2() 267} 268 269@ComponentV2 270struct Page2 { 271 // 在AppStorageV2中创建一个key为Sample的键值对(如果存在,则返回AppStorageV2中的数据),并且和prop关联 272 @Local prop: Sample = AppStorageV2.connect(Sample, () => new Sample())!; 273 pathStack: NavPathStack = new NavPathStack(); 274 275 build() { 276 NavDestination() { 277 Column() { 278 Button('Page2 connect the key Sample1') 279 .onClick(() => { 280 // 在AppStorageV2中创建一个key为Sample1的键值对(如果存在,则返回AppStorageV2中的数据),并且和prop关联 281 this.prop = AppStorageV2.connect(Sample, 'Sample1', () => new Sample())!; 282 }) 283 284 Text(`Page2 add 1 to prop.p1: ${this.prop.p1}`) 285 .fontSize(30) 286 .onClick(() => { 287 this.prop.p1++; 288 }) 289 290 Text(`Page2 add 1 to prop.p2: ${this.prop.p2}`) 291 .fontSize(30) 292 .onClick(() => { 293 // 页面不刷新,但是p2的值改变了;只有重新初始化才会改变 294 this.prop.p2++; 295 }) 296 297 // 获取当前AppStorageV2里面的所有key 298 Text(`all keys in AppStorage: ${AppStorageV2.keys()}`) 299 .fontSize(30) 300 } 301 } 302 .onReady((context: NavDestinationContext) => { 303 this.pathStack = context.pathStack; 304 }) 305 } 306} 307``` 308使用Navigation时,需要添加配置系统路由表文件src/main/resources/base/profile/route_map.json,并替换pageSourceFile为Page2页面的路径,并且在module.json5中添加:"routerMap": "$profile:route_map"。 309```json 310{ 311 "routerMap": [ 312 { 313 "name": "Page2", 314 "pageSourceFile": "src/main/ets/pages/Page2.ets", 315 "buildFunction": "Page2Builder", 316 "data": { 317 "description" : "AppStorageV2 example" 318 } 319 } 320 ] 321} 322``` 323