【最新鸿蒙应用开发】——数据存储?持久化?

数据存储

鸿蒙应用中的关于数据存储这块,分为应用状态管理存储还有一些数据持久化存储,不清楚概念的可以看我之前的前两篇文章,这边主要帮助大家区别一下状态存储和数据持久化存储的区别,避免概念和使用场景混淆。

1. localStorage和appStorage的区别,和对应的装饰器

LocalStorage

localStorage是页面级数据存储,在页面中创建实例,组件中使用@LocalStorageLink和@LocalStorageProp装饰器修饰对应的状态变量,绑定对应的组件使用比状态属性更灵活

//应用逻辑使用LocalStorage
let para: Record<string,number> = { 'PropA': 47 };
let storage: LocalStorage = new LocalStorage(para); // 创建新实例并使用给定对象初始化 , 创建实例存储数据
let propA: number | undefined = storage.get('PropA') // propA == 47 ,get()获取数据
//link():如果给定的propName在LocalStorage实例中存在,则返回与LocalStorage中propName对应属性的双向绑定数据。 (双向同步)
let link1: SubscribedAbstractProperty<number> = storage.link('PropA'); // link1.get() == 47
let link2: SubscribedAbstractProperty<number> = storage.link('PropA'); // link2.get() == 47
//prop():如果给定的propName在LocalStorage中存在,则返回与LocalStorage中propName对应属性的单向绑定数据。  (单向同步)
let prop: SubscribedAbstractProperty<number> = storage.prop('PropA'); // prop.get() == 47
link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48 //双向同步
prop.set(1); // one-way sync: prop.get() == 1; but link1.get() == link2.get() == 48 //单向同步
link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
  • new LocalStorage(数据Object)创建实例并存储数据

  • set方法,设置数据

  • get方法,获取数据

  • link方法,返回一个双向同步的变量

    • 与UI逻辑中@LocalStorageLink装饰器类似

  • prop方法,返回单向同步的变量

    • 与UI逻辑中@LocalStorageProp装饰器类似

//UI使用LocalStorage
//除了应用程序逻辑使用LocalStorage,还可以借助LocalStorage相关的两个装饰器@LocalStorageProp和@LocalStorageLink,在UI组件内部获取到LocalStorage实例中存储的状态变量。
// 创建新实例并使用给定对象初始化
let para: Record<string, number> = { 'PropA': 47 };
//这个变量一般就定义在某个@Entry组件的上方**
let storage: LocalStorage = new LocalStorage(para);
​
@Component
struct Child {
 // @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定
 @LocalStorageLink('PropA') storageLink2: number = 1;
​
 build() {
   Button(`Child from LocalStorage ${this.storageLink2}`)
     // 更改将同步至LocalStorage中的'PropA'以及Parent.storageLink1
     .onClick(() => {
       this.storageLink2 += 1
     })
 }
}
// 使LocalStorage可从@Component组件访问
@Entry(storage)//storage是上边定义的变量**
@Component
struct Parent {
 // @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定
 @LocalStorageLink('PropA') storageLink1: number = 1;
​
 build() {
   Column({ space: 15 }) {
     Button(`Parent from LocalStorage ${this.storageLink1}`) // initial value from LocalStorage will be 47, because 'PropA' initialized already
       .onClick(() => {
         this.storageLink1 += 1
       })
     // @Component子组件自动获得对CompA LocalStorage实例的访问权限。
     Child()
   }
 }
}
//上述代码:如果将LocalStorageLink改为LocalStorageProp就由双向变为了单向
  • new LocalStorage(数据Object)创建实例并存储数据

  • 父组件:

    • @Entry(LocalStorage实例) , 将LocalStorage数据注册到页面中,使得页面内部可以使用数据

    • @LocalStorageLink ,将页面变量与数据进行双向绑定,父子组件都可以使用

    • @LocalStorageProp,将页面变量与数据进行单向绑定,父子组件都可以使用

AppStorage

appStorage是进程级数据存储(==应用级的全局状态共享==),进程启动时自动创建了唯一实例,在各个页面组件中@StorageProp和@StorageLink装饰器修饰对应的状态变量。

//AppStorage是单例,它的所有API都是静态的
AppStorage.setOrCreate('PropA', 47);
​
let propA: number | undefined = AppStorage.get('PropA') // propA in AppStorage == 47
let link1: SubscribedAbstractProperty<number> = AppStorage.link('PropA'); // link1.get() == 47
let link2: SubscribedAbstractProperty<number> = AppStorage.link('PropA'); // link2.get() == 47
let prop: SubscribedAbstractProperty<number> = AppStorage.prop('PropA'); // prop.get() == 47
​
link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
prop.set(1); // one-way sync: prop.get() == 1; but link1.get() == link2.get() == 48
link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
​
AppStorage.get<number>('PropA') // == 49
link1.get() // == 49
link2.get() // == 49
prop.get() // == 49
  • 语法基本上与LocalStorage类似,只不过是静态方法

  • link双向,prop单向

AppStorage.setOrCreate('PropA', 47);
​
@Entry(storage)
@Component
struct CompA {
  @StorageLink('PropA') storageLink: number = 1;
​
  build() {
    Column({ space: 20 }) {
      Text(`From AppStorage ${this.storageLink}`)
        .onClick(() => {
          this.storageLink += 1
        })
    }
  }
}
  • @StorageLink换为@StorageProp,双向就变为单向的了

  • 不建议使用@StorageLink , 其实就是因为AppStorage共享范围太多,更新效率低下,也可能造成不必要的更新

localStorage和appStorage数据存取都是在主线程进行的,且api只提供了同步接口,存取数据时要注意数据的大小。

  • 关于存储时数据的大小问题

    • AppStorage没有大小限制,单条数据[k,v)],v也没有限制,但是不建议单条v大于1kb,大于1kb建议使用数据库。多条使用没有限制,会动态分配的。

    • LocalStorage底层实现是一个map,理论上没有大小限制。

2.LocalStorage,AppStorage,及PersistentStorage的具体实现及分别适用哪些场景

LocalStorage

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装饰的组件的同步类型不同,提供了两个装饰器:

  • @LocalStorageProp:@LocalStorageProp装饰的变量和与LocalStorage中给定属性建立单向同步关系。

  • @LocalStorageLink:@LocalStorageLink装饰的变量和在@Component中创建与LocalStorage中给定属性建立双向同步关系。

使用场景:

  • 应用逻辑使用LocalStorage

    let para: Record<string,number> = { 'PropA': 47 };
    let storage: LocalStorage = new LocalStorage(para); // 创建新实例并使用给定对象初始化
    let propA: number | undefined = storage.get('PropA') // propA == 47
    let link1: SubscribedAbstractProperty<number> = storage.link('PropA'); // link1.get() == 47
    let link2: SubscribedAbstractProperty<number> = storage.link('PropA'); // link2.get() == 47
    let prop: SubscribedAbstractProperty<number> = storage.prop('PropA'); // prop.get() == 47
    link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
    prop.set(1); // one-way sync: prop.get() == 1; but link1.get() == link2.get() == 48
    link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49

  • 从UI内部使用LocalStorage

    除了应用程序逻辑使用LocalStorage,还可以借助LocalStorage相关的两个装饰器@LocalStorageProp和@LocalStorageLink,在UI组件内部获取到LocalStorage实例中存储的状态变量。

AppStorage

AppStorage是在应用启动的时候会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。AppStorage将在应用运行过程保留其属性。属性通过唯一的键字符串值访问。

AppStorage可以和UI组件同步,且可以在应用业务逻辑中被访问。

AppStorage支持应用的主线程内多个UIAbility实例间的状态共享。

AppStorage中的属性可以被双向同步,数据可以是存在于本地或远程设备上,并具有不同的功能,比如数据持久化(详见PersistentStorage)。这些数据是通过业务逻辑中实现,与UI解耦,如果希望这些数据在UI中使用,需要用到@StorageProp@StorageLink

使用场景:

  • 从应用逻辑使用AppStorage

    AppStorage是单例,它的所有API都是静态的,使用方法类似于中LocalStorage对应的非静态方法。

    AppStorage.setOrCreate('PropA', 47);
    ​
    let storage: LocalStorage = new LocalStorage();
    storage.setOrCreate('PropA',17);
    let propA: number | undefined = AppStorage.get('PropA') // propA in AppStorage == 47, propA in LocalStorage == 17
    let link1: SubscribedAbstractProperty<number> = AppStorage.link('PropA'); // link1.get() == 47
    let link2: SubscribedAbstractProperty<number> = AppStorage.link('PropA'); // link2.get() == 47
    let prop: SubscribedAbstractProperty<number> = AppStorage.prop('PropA'); // prop.get() == 47
    ​
    link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
    prop.set(1); // one-way sync: prop.get() == 1; but link1.get() == link2.get() == 48
    link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
    ​
    storage.get<number>('PropA') // == 17
    storage.set('PropA', 101);
    storage.get<number>('PropA') // == 101
    ​
    AppStorage.get<number>('PropA') // == 49
    link1.get() // == 49
    link2.get() // == 49
    prop.get() // == 49

  • 从UI内部使用AppStorage和LocalStorage

    @StorageLink变量装饰器与AppStorage配合使用,正如@LocalStorageLink与LocalStorage配合使用一样。此装饰器使用AppStorage中的属性创建双向数据同步。

PersistentStorage

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

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

使用场景:

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

在PersistentStorage之前访问AppStorage中的属性

在PersistentStorage之后访问AppStorage中的属性

3.首选项异步存储在并发场景上的注意事项

首选项preference提供了异步存储接口,首选项的数据存储维度分为内存和沙盒,为避免内存过大导致报警,要控制首选项数据存储的数据,可以使用await来控制并发存储的问题。

4.数据存储怎么存?都用过什么数据存储?如appstorage、数据库等,这个会结合项目介绍问,可以在多看看其他存储方式及使用

  • 用户首选项实现数据持久化(Perferences)

    用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。当用户希望有一个全局唯一存储的地方,可以采用用户首选项来进行存储。Preferences会将该数据缓存在内存中,当用户读取的时候,能够快速从内存中获取数据,当需要持久化时可以使用flush接口将内存中的数据写入持久化文件中。Preferences会随着存放的数据量越多而导致应用占用的内存越大,因此,Preferences不适合存放过多的数据,适用的场景一般为应用保存用户的个性化设置(字体大小,是否开启夜间模式)等。

  • 键值型数据库实现数据持久化

    键值型数据库存储键值对形式的数据,当需要存储的数据没有复杂的关系模型,比如存储商品名称及对应价格、员工工号及今日是否已出勤等,由于数据复杂度低,更容易兼容不同数据库版本和设备类型,因此推荐使用键值型数据库持久化此类数据。

  • 关系型数据库实现数据持久化

    关系型数据库基于SQLite组件,适用于存储包含复杂关系数据的场景,比如一个班级的学生信息,需要包括姓名、学号、各科成绩等,又或者公司的雇员信息,需要包括姓名、工号、职位等,由于数据之间有较强的对应关系,复杂程度比键值型数据更高,此时需要使用关系型数据库来持久化保存数据。

  • AppStorage:应用全局的UI状态存储

    AppStorage是应用全局的UI状态存储,是和应用的进程绑定的,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储。

  • LocalStorage:页面级UI状态存储

    LocalStorage是页面级的UI状态存储,通过@Entry装饰器接收的参数可以在页面内共享同一个LocalStorage实例。LocalStorage支持UIAbility实例内多个页面间状态共享。

  • 参考链接:

相关推荐

  1. 最新鸿蒙应用开发】——数据存储持久

    2024-06-06 18:12:07       10 阅读
  2. 鸿蒙应用开发中用到的持久方案

    2024-06-06 18:12:07       10 阅读
  3. uniapp使用数据持久存储

    2024-06-06 18:12:07       9 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-06 18:12:07       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-06 18:12:07       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-06 18:12:07       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-06 18:12:07       20 阅读

热门阅读

  1. Hive on Spark、Spark on Hive的异同

    2024-06-06 18:12:07       7 阅读
  2. pyqt5 tableView实现excel拖曳填充

    2024-06-06 18:12:07       8 阅读
  3. GPT-4o版本间的对比分析和使用心得

    2024-06-06 18:12:07       9 阅读
  4. php设计模式之策略模式详解

    2024-06-06 18:12:07       12 阅读
  5. XML语法规则介绍及总结

    2024-06-06 18:12:07       9 阅读
  6. EasyExcel之动态表头导出不生效

    2024-06-06 18:12:07       8 阅读
  7. 什么叫防御式编程

    2024-06-06 18:12:07       10 阅读
  8. C++:day2

    C++:day2

    2024-06-06 18:12:07      7 阅读