LocalStorage:页面级UI状态存储
概述
LocalStorage是ArkTS为构建页面级别状态变量提供存储的内存内“数据库”。
- 应用程序可以创建多个LocalStorage实例,LocalStorage实例可以在页面内共存,也可以通过GetShared接口,实现跨页面、UIAbility实例内共享
- 组件树的根节点,即被@Entry创世的@Component,可以被分配一个LocalStorage实例,此组件的所有子组件实例将自动获得对该LocalStorage实例的访问权限。
- 被@Component装饰的组件最多可以访问一个LocalStorage实例和AppStorage,未被@Entry装饰的组件不可以被独立分配LocalStorage实例,只能接受父组件通过@Entry传递来的LocalStorage实例。一个LocalStorage实例在组件树上可以被分配给多个组件。
- LocalStorage中的所有属性都是可变的。
应用程序决定LocalStorage对象的生命周期。当应用释放最后一个指向LocalStorage的引用时,比如销毁最后一个自定义组件,LocalStorage将被JS Engine垃圾收回。
LocalStorage根据与@Component装饰的组件的同步类型不同,提供了两个装饰器:
- @LocStorageProp:@LocStorageProp装饰的变量与LocalStorage中给定属性建立单项同步关系。
- @LinkStorageLink:@LinkStorageLink装饰的变量与LocalStorage中给定属性建立双向同步关系。
限制条件
- LocalStorage创建后,命名属性的类型不可更改。后续调用Set时必须使用相同类型的值。
- LocalStorage是页面级存储,getShared接口仅能获取当前Stage通过windowStage.loadContent传入的LocalStorage实例,否则返回undefined。
LocalStorageProp
在上文中已经提到,如果要建立LocalStorage和自定义组件的联系,需要使用@LocalStorageProp和LocalStorageLink装饰器。使用@LocalStoProp(key)/@LocalStorageLink(key)装饰组件内的变量,key标识了LocalStorage的属性。
当自定义组件初始化的时候,@LocalStorageProp(key)/@LocalStorageLink(key)装饰的变量会通过给定的key,绑定LocalStorage对应的属性,完成初始化。本地初始化是必要的,因为无法保证LocalStorage一定存在给定的key(这取决于应用逻辑是否在组件初始化之前在LocalStorage实例中存入对应的属性)。
@LocalStorageProp(key)是和LocalStorage中key对应的属性建立单向数据同步,ArkUI框架支持修改@LocalStorageProp(key)在本地的值,但是对本地值的修改不会同步回LocalStorage中。相反,如果LocalStorage中key对应的属性值发生改变,例如通过set接口对LocalStorage中的值进行修改,改变会同步给@LocalStorageProp(key),并覆盖掉本地的值。
装饰器使用规则说明
| @LocalStorageProp变量装饰器 | 说明 |
|---|---|
| 装饰器参数 | key:常量字符串,必填。 |
| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组 |
| 同步类型 | 单向同步 |
| 被装饰变量的初始值 | 必须指定 |
变量的传递/访问规则说明
| 传递/访问 | 说明 |
|---|---|
| 从父节点初始化和更新 | 禁止,@LocalStorageProp不支持从父节点初始化,只能从LocalStorage对应的属性初始化,如果没有对应key的话,将使用本地默认值初始化。 |
| 初始化子节点 | 支持,可用于初始化@State、@Link、@Prop、@Provide。 |
| 是否支持组件外访问 | 否 |
观察变化和行为表现
观察变化
- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
- 当装饰的数据类型为class或者Object时,可以观察到对象整体赋值和对象属性变化。
- 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化。
- 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。详见装饰Date类型变量。
- 当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。详见装饰Map类型变量。
- 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。详见装饰Set类型变量。
框架行为
- 被@LocalStorageProp装饰的变量的值的变化不会同步回LocalStorage里。
- @LocalStorageProp装饰的变量会使单签自定义组件中关联的组件刷新。
- LocalStorage(key)中值的变化会引发所有被@LocalStorageProp对应key装饰的变量的变化,会覆盖@LocalStorageProp本地的改变。
@LocalStorageLink
如果我们需要将自定义组件的状态变量的更新同步回LocalStorage,就需要用到@LocalStorageLink。
@LocalStorageLink(key)是和LocalStorage中key对应的属性建立双向数据同步:
- 本地修改发生,该修改会被写回LocalStorage中;
- LocalStorage中的修改发生后,该修改会被同步到所有绑定LocalStorage对应key的属性上,包括单向(@LocalStorageProp和通过prop创建的单向绑定变量)、双向(@LocalStorageLink和通过link创建的双向绑定变量)变量。
装饰器使用规则说明
| @LocalStorageLink变量装饰器 | 说明 |
|---|---|
| 装饰器参数 | key:常量字符串,必填 |
| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。 |
| 同步类型 | 双向同步 |
| 被装饰变量的初始值 | 必须指定,如果LocalStorage实例中不存在属性,则用该初始值初始化该属性,并存入LocalStorage中。 |
变量的传递/访问规则说明
| 传递/访问 | 说明 |
|---|---|
| 从父节点初始化和更新 | 禁止,@LocalStorLink 不支持从父节点初始化,只能从LocalStorage中key对应的属性初始化,如果没有对应key的话,将使用本地默认值初始化 |
| 初始化子节点 | 支持,可用于初始化@State、@prop、@Link、@Provide。 |
| 是否支持组件外访问 | 否 |
观察变化和行为表现
观察变化
- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
- 当装饰的数据类型为class或者Object时,可以观察到对象整体赋值和对象属性变化(详见从ui内部使用localstorage)。
- 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化。
- 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。详见装饰Date类型变量。
- 当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。详见装饰Map类型变量。
- 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。详见装饰Set类型变量。
框架行为
- 当@LocalStorageLink(key)装饰的数值改变被观察到时,修改将被同步回LocalStorage对应属性键值key的属性中。
- LocalStorage中属性键值key对应的数据一旦改变,属性键值key绑定的所有的数据(包括双向@LocalStorageLink和单向@LocalStorageProp)都将同步修改。
- 当@LocalStorageLink(key)装饰的数据本身是状态变量,它的改变不仅仅会同步回LocalStorage中,还会引起所属的自定义组件的重新渲染。
APPStorage:应用全局的UI状态存储
APPStorage是应用全局的UI状态存储,是和应用的进程绑定的,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储。
和APPStorage不同的是,LocalStorage是页面级的,通常应用于页面内的数据共享。而APPStorage是应用级的全局窗台共享,相当于整个应用的"中枢",持久化数据PersistentStorage和环境变量Environment都是通过AppStorage中转,才可以和UI交互。
本文仅介绍APPStorage使用场景和相关的装饰器:@StorageProp和@StorageLink.
概述
APPStorage是应用启动的时候会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可以访问的。APPStorage将在应用运行过程保留其属性。属性通过卫衣的键字符串值访问。
APPStorage可以和UI组件同步,且可以在应用业务逻辑中被访问。
APPStorage支持应用的主线程内多个UIAbility实例间的状态共享。
APPStorage中的属性可以双向同步,数据可以是存在于本地或远程设备上,并且有不同的功能,比如数据持久化。这些数据是通过业务逻辑中实现,与UI解耦,如果希望这些数据在UI中使用,需要用到@StorageProp和@StorageLink。
@StorageProp
在上文中已经提到,如果要建立AppStorage和自定义组件的联系,需要使用@StorageProp和@StorageLink装饰器。使用@StorageProp(key)/@StorageLink(key)装饰组件内的变量,key标识了AppStorage的属性。
当自定义组件初始化的时候,会使用AppStorage中对应key的属性值将@StorageProp(key)/@StorageLink(key)装饰的变量初始化。由于应用逻辑的差异,无法确认是否在组件初始化之前向AppStorage实例中存入了对应的属性,所以AppStorage不一定存在key对应的属性,因此@StorageProp(key)/@StorageLink(key)装饰的变量进行本地初始化是必要的。
@StorageProp(key)是和AppStorage中key对应的属性建立单向数据同步,允许本地改变,但是对于@StorageProp,本地的修改永远不会同步回AppStorage中,相反,如果AppStorage给定key的属性发生改变,改变会被同步给@StorageProp,并覆盖掉本地的修改。
装饰器使用规则说明
| @StorageProp变量装饰器 | 说明 |
|---|---|
| 装饰器参数 | key:常量字符串,必填 |
| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组 |
| 同步类型 | 单向同步 |
| 被装饰变量的初始值 | 必须指定,如果属性不存在,则用该初始值初始化属性 |
变量的传递/访问规则说明
| 传递/访问 | 说明 |
|---|---|
| 从父节点初始化和更新 | 禁止,@StorageProp不支持从父节点初始化,只能AppStorage中key对应的属性初始化,如果没有对应key的话,将使用本地默认值初始化 |
| 初始化子节点 | 支持,可用于初始化@State、@Link、@Prop、@Provide。 |
| 是否支持组件外访问 | 否 |
观察变化和行为表现
观察变化
- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
- 当装饰的数据类型为class或者Object时,可以观察到对象整体赋值和对象属性变化(详见从ui内部使用appstorage和localstorage)。
- 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化。
- 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。详见装饰Date类型变量。
- 当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。详见装饰Map类型变量。
- 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。详见装饰Set类型变量。
框架行为
- 当@StorageProp(key)装饰的数值改变被观察到时,修改不会被同步回AppStorage对应属性键值key的属性中。
- 当前@StorageProp(key)单向绑定的数据会被修改,即仅限于当前组件的私有成员变量改变,其他的绑定该key的数据不会同步改变。
- 当@StorageProp(key)装饰的数据本身是状态变量,它的改变虽然不会同步回AppStorage中,但是会引起所属的自定义组件的重新渲染。
- 当AppStorage中key对应的属性发生改变时,会同步给所有@StorageProp(key)装饰的数据,@StorageProp(key)本地的修改将被覆盖。
@StorageLink
@StorageLink(key)是和AppStorage中key对应的属性建立双向数据同步:
- 本地修改发生,该修改会被写回AppStorage中;
- AppStorage中的修改发生后,该修改会被同步到所有绑定AppStorage对应key的属性上,包括单向(@StorageProp和通过Prop创建的单向绑定变量)、双向(@StorageLink和通过Link创建的双向绑定变量)变量和其他实例(比如PersistentStorage)。
装饰器使用规则说明
| @StorageLink变量装饰器 | 说明 |
|---|---|
| 装饰器参数 | key:常量字符串,必填 |
| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组 |
| 同步类型 | 双向同步 |
| 被装饰变量的初始值 | 必须指定,如果属性不存在,则用该初始值初始化该属性 |
变量的传递/访问规则说明
| 访问/传递 | 说明 |
|---|---|
| 从父节点初始化和更新 | 禁止 |
| 初始化子节点 | 支持,可用于初始化常规变量、@State、@Link、@Prop、@Provide。 |
| 是否支持组件外访问 | 否 |
观察变化和行为表现
观察变化
- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
- 当装饰的数据类型为class或者Object时,可以观察到对象整体赋值和对象属性变化(详见从ui内部使用appstorage和localstorage)。
- 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化。
- 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。详见装饰Date类型变量。
- 当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。详见装饰Map类型变量。
- 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。详见装饰Set类型变量。
框架行为
- 当@StorageLink(key)装饰的数值改变被观察到时,修改将被同步回AppStorage对应属性键值key的属性中。
- AppStorage中属性键值key对应的数据一旦改变,属性键值key绑定的所有的数据(包括双向@StorageLink和单向@StorageProp)都将同步修改。
- 当@StorageLink(key)装饰的数据本身是状态变量,它的改变不仅仅会同步回AppStorage中,还会引起所属的自定义组件的重新渲染。
PersistentStorage:持久化存储UI状态
前两个小节介绍的LocalStorage和APPStorage都是运行时的内存,但是在应用退出再次启动后,依然能保存选定的结果,是应用开发中十分常见的现象,这就需要用到PersisentStorage。
PersistentStorage是应用程序中的可选单例对象。此对象的作用是持久化存储选定的AppStorage属性,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同。
概述
PersistentStorage将选定的AppStorage属性保留在设备磁盘上。应用程序通过API,以决定哪些AppStorage属性应借助PersistentStorage持久化。UI和业务逻辑不直接访问PersistentStorage中的属性,所有属性访问都是对AppStorage的访问,AppStorage中的更改会自动同步到PersistentStorage。
PersistentStorage和APPStorage中的属性建立双向同步。应用开发通常通过AppStorage访问PersistentStorage,另外还有一些接口可以用于管理持久化属性,但是业务逻辑始终是通过AAppStorage获取和设置属性的。
限制条件
PersistentsStorage允许的类型和值有:
- number、string、boolean、enum等简单类型。
- 可以被JSON.stringify()和JSON.parse()重构的对象,以及对象的属性方法不支持持久化。
- API12及以上支持Map类型,可以观察到Map整体的赋值,同时可以通过调用Map的接口set、clear、delete更新Map的值。且更新的值被持久化存储。
- API12及以上支持Set类型,可以观察到Set整体的赋值,同时可以通过调用Set的接口add、clear、delete更新Set的值。且更新的值被持久化存储。
- API12及以上支持Date类型,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。且更新的值被持久化存储。详见装饰Date类型变量。
- API12及以上支持undefined 和 null。
- API12及以上支持联合类型。
PersistentStorage不允许的类型和值有:
- 不支持嵌套对象(对象数组,对象的属性是对象等)。因为目前框架无法检测AppStorage中嵌套对象(包括数组)值的变化,所以无法写回到PersistentStorage中。
持久化数据是一个相对缓慢的操作,应用程序应避免以下情况:
- 持久化大型数据集。
- 持久化经常变化的变量。
PersistentStorage的持久化变量最好是小于2kb的数据,不要大量的数据持久化,因为PersistentStorage写入磁盘的操作是同步的,大量的数据本地化读写会同步在UI线程中执行,影响UI渲染性能。如果开发者需要存储大量的数据,建议使用数据库api。
Environment:设备环境查询
开发者如果需要应用程序运行的设备的环境参数,以此来做出不同场景判断,比如多语言,暗黑模式等,需要用到Environment设备环境查询。
Environment是ArkUI框架在应用程序启动时创建的单例对象。它为AppStorage提供了一系列描述应用程序运行状态的属性。Environment的所有属性都是不可变的(即应用不可写入),所有的属性都是简单类型。
Environment内置参数
| 键 | 数据类型 | 描述 |
|---|---|---|
| accessibilityEnabled | boolean | 获取无障碍屏幕读取是否启用。 |
| colorMode | ColorMode | 色彩模型类型:选项为ColorMode.LIGHT: 浅色,ColorMode.DARK: 深色。 |
| fontScale | number | 字体大小比例,范围: [0.85, 1.45]。 |
| fontWeightScale | number | 字体粗细程度,范围: [0.6, 1.6]。 |
| layoutDirection | LayoutDirection | 布局方向类型:包括LayoutDirection.LTR: 从左到右,LayoutDirection.RTL: 从右到左。 |
| languageCode | string | 当前系统语言值,取值必须为小写字母, 例如zh。 |
限制条件
Environment和UIContext相关联,需要在UIContext明确的时候才可以调用。可以通过在runScopedTask里明确上下文。如果没有在UIContext明确的地方调用,将导致无法查询到设备环境数据。