🎉 博客主页:【剑九_六千里-CSDN博客】【剑九_六千里-掘金社区】
🎨 上一篇文章:【HarmonyOS第六章:组件状态共享(父子组件传参、多层级组件传参、@Watch监听状态变化、@Observed与@ObjectLink、多层嵌套数据更新)】
🎠 系列专栏:【HarmonyOS系列】
💖 感谢大家点赞👍收藏⭐评论✍
文章目录
- 1. PersistentStorage
- 1.1. 简单数据类型的持久化,获取和修改
- 1.1.1. 语法
- 1.1.2. 使用示例
- 1.2. 复杂数据类型的持久化,获取和修改
- 1.2.1. 基本使用
- 1.2.2. 使用 AppStorage.get() 获取数据,AppStorage.set()写入数据
- 1.2.3. 使用 link 写入/获取数据
- 1.3. 在其它页面获取存储的数据
- 2. LocalStorage
- 2.1. 基本使用
- 2.2. 页面内共享
- 2.2.1. 声明
- 2.2.2. 接收
- 2.2.3. 完整示例
- 2.3. 不同页面间共享
- 2.4. LocalStorage 存储的数据并不会持久化存储
- 3. AppStorage
- 3.1. 基础用法
- 3.2. 组件共享
- 3.3. set() 及 get() 方法
- 3.4. AppStorage.link("user");
- 4. 总结
1. PersistentStorage
PersistentStorage
允许将选定的 AppStorage
属性保留在设备磁盘上,以便在应用程序关闭后仍然保持持久化。以下是关于PersistentStorage
的一些细节和注意事项:
UI
和业务逻辑不应直接访问PersistentStorage
中的属性,所有属性访问都应通过AppStorage
进行。任何在AppStorage
中的更改都会自动同步到PersistentStorage
。PersistentStorage
支持存储简单类型数据,如数字(number
)、字符串(string
)、布尔(boolean
)、枚举(enum
)等。- 如果需要存储对象类型的数据,可以将其转换为
JSON
字符串后再存储。 - 注意,持久化变量最好是小于
2KB
的数据。如果开发者需要存储大量的数据,建议使用数据库API来进行管理和存储。
1.1. 简单数据类型的持久化,获取和修改
1.1.1. 语法
// 1. 通过 PersistentStorage.persistProp() 定义要存储的数据
// 参数一:存储的属性;参数二:存储的值
PersistentStorage.persistProp("xxx", xxx)// 2. 通过 @StorageProp() 或 @StorageLink() 接收数据
@StorageProp("xxx")
@StorageLink("xxx")// 3. 接收数据
xxx: number = 0;// 4. 通过 this.xxx 使用数据
this.xxx
1.1.2. 使用示例
使用 PersistentStorage
存储数据,使用 @StorageLink
或 @StorageLink
接收数据,同时数据支持修改:
// PersistentStorage 写入磁盘-app关闭数据依然存在,持久化存储
// 存储简单数据类型:number string boolean等等
// 存储负载数据类型:array object function
PersistentStorage.PersistProp("num",100)@Entry
@Component
struct Index {@StorageLink("num") // 获取数据,单向数据流,只是组件内可以改变数据,并不会写入 PersistentStorage// @StorageLink("num") // 获取数据,双向数据流,本地修改会同步写入到 PersistentStoragenum:number=0 // 如果未存储,默认初始值build() {Column({space:10}) {Text(`${this.num}`)Button("修改age").onClick(()=>{this.num++})}.width('100%').height('100%')}
}
1.2. 复杂数据类型的持久化,获取和修改
1.2.1. 基本使用
- 注意:存储复杂类型数据时,value 必须是json
// 注意:存储复杂类型数据时,value 必须是json
PersistentStorage.persistProp("user", JSON.stringify({name: "张三", age: 18}))
interface User {name: string;age: number;
}@Entry
@Component
struct Index {@StorageLink("user") // 获取数据 @StorageLink("user") 或 @StorageProp("user")userInfo: string = "{}" // 默认值@State user: User = JSON.parse(this.userInfo); // 将接收到的json转成objectbuild() {Column() {Text(`${this.user.name}--${this.user.age}`) // 使用传入的数据Button("修改Age").onClick(() => {this.user.age++;})}.width("100%").height("100%")}
}
1.2.2. 使用 AppStorage.get() 获取数据,AppStorage.set()写入数据
这个例子中使用 @StorageLink("user")
获取数据,可以实现需求,同时我们也可以使用 AppStorage.get()
来获取数据:
// 注意:存储复杂类型数据时,value 必须是json
PersistentStorage.persistProp("user", JSON.stringify({name: "张三", age: 18}))
interface User {name: string;age: number;
}@Entry
@Component
struct Index {@StorageLink("user")userInfo: string = "{}"@State user: User = JSON.parse(this.userInfo); // 将接收到的json转成objectbuild() {Column() {Text(`${this.user.name}--${this.user.age}`) // 使用传入的数据Button("修改Age").onClick(() => {this.user.age++;})Button("获取user").onClick(() => {const res = AppStorage.get<string>("user") // 获取到的是原数据console.log(res)})}.width("100%").height("100%")}
}
此时点击修改Age按钮,可以发现age被改变了,但 AppStorage.get()
获取到的是改变前的数据,此时可以通过 AppStorage.set()
重新设置数据 :
// 注意:存储复杂类型数据时,value 必须是json
PersistentStorage.persistProp("user", JSON.stringify({name: "张三", age: 18}))
interface User {name: string;age: number;
}@Entry
@Component
struct Index {@StorageLink("user")userInfo: string = "{}"@State user: User = JSON.parse(this.userInfo); // 将接收到的json转成objectbuild() {Column() {Text(`${this.user.name}--${this.user.age}`) // 使用传入的数据Button("修改Age").onClick(() => {this.user.age++;AppStorage.set<string>("user", JSON.stringify(this.user)); // 将修改后的数据重新存储})Button("获取user").onClick(() => {const res = AppStorage.get<string>("user")console.log(res)})}.width("100%").height("100%")}
}
1.2.3. 使用 link 写入/获取数据
// 注意:存储复杂类型数据时,value 必须是jsonPersistentStorage.persistProp("user", JSON.stringify({name: "张三", age: 18}))
interface User {name: string;age: number;
}@Entry
@Component
struct Index {@StorageLink("user")@Watch("update")userInfo: string = "{}"@State user: User = JSON.parse(this.userInfo); // 将接收到的json转成objectupdate() {this.user = JSON.parse(this.userInfo)}build() {Column() {Text(`${this.user.name}--${this.user.age}`) // 使用传入的数据Button("修改Age").onClick(() => {this.user.age++;// 将修改后的数据重新存储AppStorage.set<string>("user", JSON.stringify(this.user));})Button("AppStorage.get获取user").onClick(() => {// 获取数据const res = AppStorage.get<string>("user")console.log(res)})Button("Link 方式 获取/写入user").onClick(() => {// 获取数据const userLink: SubscribedAbstractProperty<string> = AppStorage.link("user")console.log(userLink.get())userLink.set(JSON.stringify({name: "李四", age: 21}))})}.width("100%").height("100%")}
}
1.3. 在其它页面获取存储的数据
测试步骤如下:
- 修改主页面 age;
- 点击跳转页面,跳转到其它页面;
- 查看其它页面获取的数据是否正确;
- 修改其它页面的数据;
- 返回主页面,查看主页面数据是否同步更新;
通过 router
跳转页面:
// 注意:存储复杂类型数据时,value 必须是json
import router from '@ohos.router'; // 导入路由模块PersistentStorage.persistProp("user", JSON.stringify({name: "张三", age: 18}))
interface User {name: string;age: number;
}@Entry
@Component
struct PersistentStorage3 {@StorageLink("user")@Watch("update")userInfo: string = "{}"@State user: User = JSON.parse(this.userInfo); // 将接收到的json转成objectupdate() {this.user = JSON.parse(this.userInfo)}build() {Column() {Text(`${this.user.name}--${this.user.age}`) // 使用传入的数据Button("修改Age").onClick(() => {this.user.age++;// 将修改后的数据重新存储AppStorage.set<string>("user", JSON.stringify(this.user));})Button("AppStorage.get获取user").onClick(() => {// 获取数据const res = AppStorage.get<string>("user")console.log(res)})Button("Link 方式 获取/写入user").onClick(() => {// 获取数据const userLink: SubscribedAbstractProperty<string> = AppStorage.link("user")console.log(userLink.get())userLink.set(JSON.stringify({name: "李四", age: 21}))})Button("跳转页面").onClick(() => {// 路由跳转router.pushUrl({url: "pages/PersistentStorage4"})})}.width("100%").height("100%")}
}
路由跳转要求页面必须在 src/main/resources/base/profile/main_pages.json
中进行配置:
PersistentStorage3
页面初始数据为 18 :
点击 PersistentStorage3
修改Age,并点击跳转到 PersistentStorage4
页面,可以看到 PersistentStorage4
页面获取到了更新后的数据:
在 PersistentStorage4
页面修改Age:
返回 PersistentStorage3
页面,可以看到数据也更新了:
因此,使用 PersistentStorage.persistProp()
存储的数据,在所有页面中都可以使用并修改。
2. LocalStorage
LocalStorage
是用于页面级的UI状态存储,通过 @Entry
装饰器接收的参数可以在同一页面内共享相同的LocalStorage
实例。此外,LocalStorage
也可以在 UIAbility
内,在不同页面之间共享状态数据。
2.1. 基本使用
2.2. 页面内共享
2.2.1. 声明
使用 const storage = new LocalStorage({ key: value })
来创建LocalStorage
实例,其中 key
是存储的键名,value
是初始值。
interface User {name: string;age: number;
}const user: User = { name: '张三', age: 18 };
const storage = new LocalStorage(user);
2.2.2. 接收
@Entry
构造器接收一个参数,该参数是通过const storage = new LocalStorage(user);
存储的数据
@Entry(storage)
- 单向数据绑定:使用
@LocalStorageProp('user')
装饰器,可以在组件内对LocalStorage
的值进行单向修改,仅在组件内生效。 - 双向数据绑定:使用
@LocalStorageLink('user')
装饰器,可以实现全局范围内对LocalStorage
的值进行双向修改,多个组件可以共享相同的LocalStorage
实例。
// @LocalStorageProp("user")
@LocalStorageLink("user")
2.2.3. 完整示例
// 非持久化,只能在一个 UIAbility 中使用
interface User {name: string;age: number;
}const user: User = { name: '张三', age: 18 };
const storage = new LocalStorage(user);@Entry(storage)
@Component
struct Index {// @LocalStorageProp("user") // 使用@LocalStorageProp("user")时,修改值,子组件不会同步@LocalStorageLink("user") // 使用@LocalStorageLink("user")时,修改值,子组件会同步userInfo: User = { name: "李四", age: 18 } // 默认值build() {Column() {Text(`${this.userInfo.name}---${this.userInfo.age}`)Button("Index修改age").onClick(() => {this.userInfo.age++;})ChildA()ChildB()}.width('100%')}
}@Component
struct ChildA {@LocalStorageProp("user")userInfo: User = { name: "Tom", age: 20 }build() {Column({ space: 10 }) {Text(`${this.userInfo.name}---${this.userInfo.age}`).fontColor(Color.White)Button("ChildA修改age").onClick(() => {// @LocalStorageProp("user") 接收的参数,子组件修改时,父组件不会同步this.userInfo.age++})}.width('100%').height(100).backgroundColor(Color.Blue)}
}@Component
struct ChildB {@LocalStorageLink("user")userInfo: User = { name: "Tom", age: 20 }build() {Column({ space: 10 }) {Text(`${this.userInfo.name}---${this.userInfo.age}`).fontColor(Color.White)Button("ChildB修改age").onClick(() => {// @LocalStorageLink("user") 接收的参数,子组件修改时,父组件会同步this.userInfo.age++})}.width('100%').height(100).backgroundColor(Color.Brown)}
}
2.3. 不同页面间共享
-
创建一个
IndexOther.ets
文件
-
将
IndexOther.ets
加入到路由中
-
在
UIAbility
中创建LocalStorage
:可以在UIAbility
中创建LocalStorage
实例,并通过loadContent
方法提供给加载的窗口,以便在页面间共享状态数据。
-
在页面中获取
LocalStorage
实例:在页面中,可以通过const storage = LocalStorage.getShared()
来获取LocalStorage的实例。然后,可以通过@Entry(storage)
将实例传递给页面,以便在页面中使用LocalStorage
来共享和管理状态数据。
// Index.etsimport router from "@ohos.router";
interface User {name: string;age: number;
}
const storage = LocalStorage.getShared();@Entry(storage)
@Component
struct Index {@LocalStorageLink("user")userInfo: User = { name: "李四", age: 18 } // 默认值build() {Column() {Text("这是Index页面")Text(`${this.userInfo.name}---${this.userInfo.age}`)Button("Index修改age").onClick(() => {this.userInfo.age++;})Button("跳转到IndexOther页面").onClick(() => {router.pushUrl({url: "pages/IndexOther"})})}.width('100%')}
}// IndexOther.ets
import router from "@ohos.router";// 非持久化,只能在一个 UIAbility 中使用
interface UserInfo {name: string;age: number;
}const storage = LocalStorage.getShared();@Entry(storage)
@Component
struct IndexOther {@LocalStorageLink("user")userInfo: UserInfo = { name: "李四", age: 18 } // 默认值build() {Column() {Text("这是IndexOther页面")Text(`${this.userInfo.name}---${this.userInfo.age}`)Button("Index修改age").onClick(() => {this.userInfo.age++;})Button("跳转到Index页面").onClick(() => {router.pushUrl({url: "pages/Index"})})}.width('100%')}
}
此时不论在哪一个页面修改数据,都会同步:
2.4. LocalStorage 存储的数据并不会持久化存储
打开模拟机:
初始值如下:
修改数据:
关闭当前页面:
再次打开后发现数据已经变成了初始值,因此 LocalStorage
存储的数据并不会持久化存储:
3. AppStorage
AppStorage 是应用程序级别的全局UI状态存储,与应用程序的进程绑定。它由UI框架在应用程序启动时创建,用于中央存储应用程序的UI状态属性。
3.1. 基础用法
- 初始化使用:可以使用
AppStorage.SetOrCreate(key, value)
来初始化AppStorage中的数据,其中key
是存储的键名,value
是初始值。 - 单向数据绑定:使用
@StorageProp('user')
装饰器,可以在组件内对AppStorage
的值进行单向修改,仅在组件内生效。 - 双向数据绑定:使用
@StorageLink('user')
装饰器,可以实现全局范围内对AppStorage
的值进行双向修改,多个组件可以共享相同的AppStorage
实例,从而实现全局状态管理。
interface Person {name: string;age: number;
}const user: Person = { name: "张三", age: 18 }
AppStorage.setOrCreate<Person>("user", user)@Entry
@Component
struct Index {// @StorageProp("user")@StorageLink("user")userInfo: Person = { name: "李四", age: 28 } // 默认值build() {Column() {Text(`${this.userInfo.name}---${this.userInfo.age}`)Button("修改age").onClick(() => {this.userInfo.age++;})}.width("100%").height("100%")}
}
3.2. 组件共享
子组件中可共享源数据:
interface Person {name: string;age: number;
}const user: Person = { name: "张三", age: 18 }
AppStorage.setOrCreate<Person>("user", user)@Entry
@Component
struct Index {// @StorageProp("user")@StorageLink("user")userInfo: Person = { name: "李四", age: 28 } // 默认值build() {Column() {Text(`${this.userInfo.name}---${this.userInfo.age}`)Button("直接修改age").onClick(() => {this.userInfo.age++;})ChildA()}.width("100%").height("100%")}
}@Component
struct ChildA {@StorageProp("user") // 不会同步// @StorageLink("user") // 会同步user: Person = { name: "Tom", age: 20 }build() {Column({ space: 10 }) {Text(this.user.name + "----" + this.user.age).fontColor(Color.White)Button("ChildA修改age").onClick(() => {this.user.age++})}.width('100%').height(100).backgroundColor(Color.Blue)}
}
3.3. set() 及 get() 方法
- 使用
AppStorage.set<ValueType>(key, value)
可以覆盖AppStorage
中的数据,其中key
是存储的键名,value
是要存储的新值。 - 使用
AppStorage.get<ValueType>(key)
可以获取AppStorage
中存储的数据,其中ValueType
是数据的类型,key
是存储的键名。
interface Person {name: string;age: number;
}const user: Person = { name: "张三", age: 18 }
AppStorage.setOrCreate<Person>("user", user)@Entry
@Component
struct Index {// @StorageProp("user")@StorageLink("user")userInfo: Person = { name: "李四", age: 28 } // 默认值build() {Column() {Text(`${this.userInfo.name}---${this.userInfo.age}`)Button("直接修改age").onClick(() => {this.userInfo.age++;})Button("通过set修改age").onClick(() => {AppStorage.set<Person>("user", { name: "李四", age: 28 })})Button("通过get获取user").onClick(() => {const user = AppStorage.get<Person>("user")console.log(`${user?.name}---${user?.age}`)})}.width("100%").height("100%")}
}
3.4. AppStorage.link(“user”);
- 使用
const link: SubscribedAbstractProperty<ValueType> = AppStorage.Link(key)
可以创建一个与AppStorage中数据关联的链接,通过这个链接可以修改和获取数据。您可以使用link.set(value)
来修改数据,使用link.get()
来获取数据。这个链接允许您在不同组件之间共享数据,并保持数据的同步。
4. 总结
LocalStorage
– 一个UIAbility
状态(内存–非持久化–非全应用)AppStorage
– 应用内状态–多UIAbility
共享(内存–非持久化-退出App应用 数据消失)PersistenStroage
–全局持久化状态(写入磁盘–持久化状态-退出App应用 数据不消失)