HarmonyOS 应用级状态管理
1. LocalStorage:页面级UI状态存储
1.1 概念
LocalStorage是页面级的UI状态存储,通过@Entry装饰器接收的参数可以在页面内共享同一个LocalStorage实例。LocalStorage也可以在UIAbility内,页面间共享状态。
应用程序可以创建多个LocalStorage实例,LocalStorage实例可以在页面内共享,也可以通过GetShared接口,获取在UIAbility里创建的GetShared,实现跨页面、UIAbility内共享。 组件树的根节点,即被@Entry装饰的@Component,可以被分配一个LocalStorage实例,此组件的所有子组件实例将自动获得对该LocalStorage实例的访问权限; 被@Component装饰的组件最多可以访问一个LocalStorage实例和AppStorage,未被@Entry装饰的组件不可被独立分配LocalStorage实例,只能接受父组件通过@Entry传递来的LocalStorage实例。一个LocalStorage实例在组件树上可以被分配给多个组件。 LocalStorage中的所有属性都是可变的
1.2 应用逻辑使用LocalStorage
const storage = new LocalStorage ( { name: "李四" } )
storage. set ( 'name' , '张三' )
console . log ( storage. get ( "name" ) )
@Entry
@Component
struct LearnStorage {
@State message: string = 'Hello World'
build ( ) {
Row ( ) {
Column ( ) {
Text ( this . message)
. fontSize ( 50 )
. fontWeight ( FontWeight. Bold)
}
. width ( '100%' )
}
. height ( '100%' )
}
}
1.3 从UI内部使用LocalStorage(双向同步)
除了应用程序逻辑使用LocalStorage,还可以借助LocalStorage相关的两个装饰器@LocalStorageProp和@LocalStorageLink,在UI组件内部获取到LocalStorage实例中存储的状态变量。
1.3.1 例子
使用构造函数创建LocalStorage实例storage; 使用@Entry装饰器将storage添加到LearnStorage顶层组件中; @LocalStorageLink绑定LocalStorage对给定的属性,建立双向数据同步
@Component
struct Child {
@LocalStorageLink ( 'name' ) storageName: string = '张三' ;
build ( ) {
Column ( ) {
Text ( '子组件---' + this . storageName)
}
}
}
const storage = new LocalStorage ( { } )
@Entry ( storage)
@Component
struct LearnStorage {
@LocalStorageLink ( 'name' ) storageName: string = '张三' ;
build ( ) {
Row ( ) {
Column ( ) {
Text ( this . storageName)
. fontSize ( 50 )
. fontWeight ( FontWeight. Bold)
Button ( '看看Storage' ) . onClick ( ( ) => {
this . storageName = '王五'
console . log ( storage. get ( 'name' ) )
} )
Child ( )
}
. width ( '100%' )
}
. height ( '100%' )
}
}
1.4 从UI内部使用LocalStorage(单向同步)
@Component
struct Child {
@LocalStorageProp ( 'name' ) storageName: string = '张三' ;
build ( ) {
Column ( ) {
Text ( '子组件---' + this . storageName)
}
}
}
const storage = new LocalStorage ( { } )
@Entry ( storage)
@Component
struct LearnStorage {
@LocalStorageProp ( 'name' ) storageName: string = '张三' ;
build ( ) {
Row ( ) {
Column ( ) {
Text ( this . storageName)
. fontSize ( 50 )
. fontWeight ( FontWeight. Bold)
Button ( '看看Storage' ) . onClick ( ( ) => {
this . storageName = '王五'
console . log ( storage. get ( 'name' ) )
} )
Child ( )
}
. width ( '100%' )
}
. height ( '100%' )
}
}
1.5 将LocalStorage实例从UIAbility共享到一个或多个视图(全局共享)
上面的实例中,LocalStorage的实例仅仅在一个@Entry装饰的组件和其所属的子组件(一个页面)中共享,如果希望其在多个视图中共享,可以在所属UIAbility中创建LocalStorage实例,并调用windowStage.loadContent。
1.5.1 EntryAbility
import UIAbility from '@ohos.app.ability.UIAbility' ;
import hilog from '@ohos.hilog' ;
import window from '@ohos.window' ;
const localStorage: LocalStorage = new LocalStorage ( { globalName: "全局的名字" } ) ;
export default class EntryAbility extends UIAbility {
storage: LocalStorage = localStorage
onCreate ( want, launchParam) {
hilog. info ( 0x0000 , 'testTag' , '%{public}s' , 'Ability onCreate' ) ;
}
onDestroy ( ) {
hilog. info ( 0x0000 , 'testTag' , '%{public}s' , 'Ability onDestroy' ) ;
}
async onWindowStageCreate ( windowStage: window. WindowStage) {
windowStage. loadContent ( 'pages/LearnStorage' , this . storage) ;
}
onWindowStageDestroy ( ) {
hilog. info ( 0x0000 , 'testTag' , '%{public}s' , 'Ability onWindowStageDestroy' ) ;
}
onForeground ( ) {
hilog. info ( 0x0000 , 'testTag' , '%{public}s' , 'Ability onForeground' ) ;
}
onBackground ( ) {
hilog. info ( 0x0000 , 'testTag' , '%{public}s' , 'Ability onBackground' ) ;
}
}
1.5.2 页面中使用
const storage = LocalStorage. GetShared ( )
console . log ( JSON . stringify ( storage) )
@Entry ( storage)
@Component
struct LearnStorage {
@LocalStorageLink ( 'globalName' ) globalName: string = '李四' ;
build ( ) {
Row ( ) {
Column ( ) {
Text ( this . globalName)
. fontSize ( 50 )
. fontWeight ( FontWeight. Bold)
Button ( '看看Storage' ) . onClick ( ( ) => {
this . globalName = '王五'
console . log ( storage. get ( 'name' ) )
} )
}
. width ( '100%' )
}
. height ( '100%' )
}
}
2.AppStorage:应用全局的UI状态存储
2.1 概念
AppStorage是应用全局的UI状态存储,是和应用的进程绑定的,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储。 和AppStorage不同的是,LocalStorage是页面级的,通常应用于页面内的数据共享。而AppStorage是应用级的全局状态共享,还相当于整个应用的“中枢”,持久化数据PersistentStorage和环境变量Environment都是通过和AppStorage中转,才可以和UI交互。 AppStorage是在应用启动的时候会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。AppStorage将在应用运行过程保留其属性。属性通过唯一的键字符串值访问。 AppStorage可以和UI组件同步,且可以在应用业务逻辑中被访问。 AppStorage中的属性可以被双向同步,数据可以是存在于本地或远程设备上,并具有不同的功能,比如数据持久化(详见PersistentStorage)。这些数据是通过业务逻辑中实现,与UI解耦,如果希望这些数据在UI中使用,需要用到@StorageProp和@StorageLink
2.2 从应用逻辑使用AppStorage
AppStorage是单例,它的所有API都是静态的
AppStorage. SetOrCreate ( 'name' , 'app的名字' ) ;
console . log ( AppStorage. Get ( 'name' ) )
@Entry ( )
@Component
struct LearnStorage {
build ( ) {
Row ( ) {
Column ( ) {
Text ( '哈哈哈' )
}
. width ( '100%' )
}
. height ( '100%' )
}
}
2.3 从UI内部使用AppStorage
@StorageLink变量装饰器与AppStorage配合使用,正如@LocalStorageLink与LocalStorage配合使用一样。此装饰器使用AppStorage中的属性创建双向数据同步
AppStorage. SetOrCreate ( 'name' , 'app的名字' ) ;
console . log ( AppStorage. Get ( 'name' ) )
@Entry ( )
@Component
struct LearnStorage {
@StorageLink ( 'name' ) name: string = '李四'
build ( ) {
Row ( ) {
Column ( ) {
Text ( this . name)
Button ( '查看数据' )
. onClick ( ( ) => {
this . name = '王五'
console . log ( AppStorage. Get ( 'name' ) )
} )
}
. width ( '100%' )
}
. height ( '100%' )
}
}
3.PersistentStorage:持久化存储UI状态
3.1 概念
PersistentStorage将选定的AppStorage属性保留在设备磁盘上。应用程序通过API,以决定哪些AppStorage属性应借助PersistentStorage持久化。UI和业务逻辑不直接访问PersistentStorage中的属性,所有属性访问都是对AppStorage的访问,AppStorage中的更改会自动同步到PersistentStorage。 PersistentStorage和AppStorage中的属性建立双向同步。应用开发通常通过AppStorage访问PersistentStorage,另外还有一些接口可以用于管理持久化属性,但是业务逻辑始终是通过AppStorage获取和设置属性的。
3.2 注意
3.2.1 允许的类型和值
使用简单类型如 number, string, boolean, enum。
可以使用 JSON.stringify() 和 JSON.parse() 的对象,但不支持内置类型如 Date, Map, Set。
3.2.2 不允许的类型和值
避免嵌套对象,包括对象数组和对象属性是对象。
不支持 undefined 和 null。
3.2.3 最佳实践和限制
避免持久化大型和经常变化的数据。
持久化变量最好小于 2kb。
不要过度持久化数据,可能影响 UI 渲染性能。
对于大量数据存储需求,建议使用数据库 API。
仅在 UI 页面内使用 PersistentStorage,否则无法持久化数据
3.3 使用
PersistentStorage. PersistProp ( 'token' , '后端获取的token' ) ;
console . log ( AppStorage. Get ( 'token' ) )
@Entry ( )
@Component
struct LearnStorage {
@StorageLink ( 'token' ) token: string = ''
build ( ) {
Row ( ) {
Column ( ) {
Text ( this . token)
Button ( '修改数据' )
. onClick ( ( ) => {
this . token = '修改的token,并且持久化'
} )
}
. width ( '100%' )
}
. height ( '100%' )
}
}