HarmonyOS NEXT应用开发之PersistentStorage:持久化存储UI状态

前两个小节介绍的LocalStorage和AppStorage都是运行时的内存,但是在应用退出再次启动后,依然能保存选定的结果,是应用开发中十分常见的现象,这就需要用到PersistentStorage。

PersistentStorage是应用程序中的可选单例对象。此对象的作用是持久化存储选定的AppStorage属性,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同。

概述

PersistentStorage将选定的AppStorage属性保留在设备磁盘上。应用程序通过API,以决定哪些AppStorage属性应借助PersistentStorage持久化。UI和业务逻辑不直接访问PersistentStorage中的属性,所有属性访问都是对AppStorage的访问,AppStorage中的更改会自动同步到PersistentStorage。

PersistentStorage和AppStorage中的属性建立双向同步。应用开发通常通过AppStorage访问PersistentStorage,另外还有一些接口可以用于管理持久化属性,但是业务逻辑始终是通过AppStorage获取和设置属性的。

限制条件

PersistentStorage允许的类型和值有:

  • 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的属性。且更新的值被持久化存储。
  • API12及以上支持undefinednull
  • API12及以上[支持联合类型。

PersistentStorage不允许的类型和值有:

  • 不支持嵌套对象(对象数组,对象的属性是对象等)。因为目前框架无法检测AppStorage中嵌套对象(包括数组)值的变化,所以无法写回到PersistentStorage中。

持久化数据是一个相对缓慢的操作,应用程序应避免以下情况:

  • 持久化大型数据集。
  • 持久化经常变化的变量。

PersistentStorage的持久化变量最好是小于2kb的数据,不要大量的数据持久化,因为PersistentStorage写入磁盘的操作是同步的,大量的数据本地化读写会同步在UI线程中执行,影响UI渲染性能。如果开发者需要存储大量的数据,建议使用数据库api。

PersistentStorage和UI实例相关联,持久化操作需要在UI实例初始化成功后(即 loadContent 传入的回调被调用时)才可以被调用,早于该时机调用会导致持久化失败。

// EntryAbility.ets
onWindowStageCreate(windowStage: window.WindowStage): void {
   
   
  windowStage.loadContent('pages/Index', (err) => {
   
   
    if (err.code) {
   
   
      return;
    }
    PersistentStorage.persistProp('aProp', 47);
  });
}

使用场景

从AppStorage中访问PersistentStorage初始化的属性

  1. 初始化PersistentStorage:
   PersistentStorage.persistProp('aProp', 47);
  1. 在AppStorage获取对应属性:
   AppStorage.get<number>('aProp'); // returns 47

或在组件内部定义:

   @StorageLink('aProp') aProp: number = 48;

完整代码如下:

PersistentStorage.persistProp('aProp', 47);

@Entry
@Component
struct Index {
   
   
  @State message: string = 'Hello World'
  @StorageLink('aProp') aProp: number = 48

  build() {
   
   
    Row() {
   
   
      Column() {
   
   
        Text(this.message)
        // 应用退出时会保存当前结果。重新启动后,会显示上一次的保存结果
        Text(`${
     
     this.aProp}`)
          .onClick(() => {
   
   
            this.aProp += 1;
          })
      }
    }
  }
}
  • 新应用安装后首次启动运行:

    1. 调用persistProp初始化PersistentStorage,首先查询在PersistentStorage本地文件中是否存在“aProp”,查询结果为不存在,因为应用是第一次安装。
    2. 接着查询属性“aProp”在AppStorage中是否存在,依旧不存在。
    3. 在AppStorge中创建名为“aProp”的number类型属性,属性初始值是定义的默认值47。
    4. PersistentStorage将属性“aProp”和值47写入磁盘,AppStorage中“aProp”对应的值和其后续的更改将被持久化。
    5. 在Index组件中创建状态变量@StorageLink(‘aProp’) aProp,和AppStorage中“aProp”双向绑定,在创建的过程中会在AppStorage中查找,成功找到“aProp”,所以使用其在AppStorage找到的值47。

    图1 PersistProp初始化流程

  • 触发点击事件后:

    1. 状态变量@StorageLink(‘aProp’) aProp改变,触发Text组件重新刷新。
    2. @StorageLink装饰的变量是和AppStorage中建立双向同步的,所以@StorageLink(‘aProp’) aProp的变化会被同步回AppStorage中。
    3. AppStorage中“aProp”属性的改变会同步到所有绑定该“aProp”的单向或者双向变量,在本示例中没有其他的绑定“aProp”的变量。
    4. 因为“aProp”对应的属性已经被持久化,所以在AppStorage中“aProp”的改变会触发PersistentStorage,将新的改变写入本地磁盘。
  • 后续启动应用:

    1. 执行PersistentStorage.persistProp(‘aProp’, 47),在首先查询在PersistentStorage本地文件查询“aProp”属性,成功查询到。
    2. 将在PersistentStorage查询到的值写入AppStorage中。
    3. 在Index组件里,@StorageLink绑定的“aProp”为PersistentStorage写入AppStorage中的值,即为上一次退出应用存入的值。

在PersistentStorage之前访问AppStorage中的属性

该示例为反例。在调用PersistentStorage.persistProp或者persistProps之前使用接口访问AppStorage中的属性是错误的,因为这样的调用顺序会丢失上一次应用程序运行中的属性值:

let aProp = AppStorage.setOrCreate('aProp', 47
### 关于 OpenHarmony 持久化存储的技术分析 在 OpenHarmony 开发中,持久化存储是一个重要的功能模块,它允许应用程序将数据保存到设备上以便后续访问。以下是几种常用的持久化存储技术和方法: #### 1. **关系型数据库** 使用关系型数据库是一种常见且强大的持久化方式。通过 SQL 查询语句操作表结构,能够高效管理复杂的数据关联和事务处理。对于鸿蒙开发而言,支持的关系型数据库通常基于 SQLite 或其他轻量级实现[^3]。 ```sql -- 创建一张用户信息表 CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL, password TEXT NOT NULL ); -- 插入一条新记录 INSERT INTO users (username, password) VALUES ('admin', 'password'); ``` #### 2. **键值对存储 PersistentStorage** 对于小型、简单的数据需求,`PersistentStorage` 提供了一种便捷的方式来存储不超过 2KB 的键值对数据。然而需要注意的是,由于其同步写入机制可能会阻塞 UI 渲染线程,因此不适合大规模数据存储场景[^5]。 ```javascript import featureAbility from '@ohos.ability.featureAbility'; let context = featureAbility.getContext(); try { await context.persistentStorage.put('key_name', 'value_content'); // 存储单条数据 const value = await context.persistentStorage.get('key_name'); // 获取指定 key 值 } catch (err) { console.error(`Error occurred while using persistent storage: ${err}`); } ``` #### 3. **文件系统 File I/O** 如果需要更灵活地控制数据格式或者存储二进制大对象,则可以直接利用文件系统的 API 进行读写操作。这种方式适用于日志记录、配置文件以及媒体资源等场合[^2]。 ```typescript import fileio from '@ohos.file.io'; async function writeToFile(filePath: string, content: string): Promise<void> { await fileio.writeFile(filePath, content, { append: false }); } async function readFromFile(filePath: string): Promise<string | undefined> { return new Promise((resolve, reject) => { fileio.readFile(filePath, 'utf8').then(data => resolve(data)).catch(err => reject(err)); }); } ``` #### 4. **分布式数据服务 Distributed Data Service (DDS)** 当涉及到跨设备间共享数据时,OpenHarmony 提供了 DDS 功能来简化这一过程。借助该框架不仅可以完成本地化的持久化工作,还能够无缝衔接远程节点上的对应副本更新逻辑[^1]。 --- ### 总结 综上所述,在实际项目选型过程中应综合考虑具体业务诉求与性能指标权衡选用合适的方案组合。例如针对少量偏好设置推荐采用 `PersistentStorage`; 若存在较多结构性较强的内容则优先倾向传统意义上的 RDBMS; 至于那些体积庞大又难以压缩成单一实体的对象类素材更适合交由专门定制过的流式接口负责传输加载任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值