HarmonyOS开发 - 本地持久化之实现LocalStorage支持多实例

news/2024/10/27 12:31:25/

        用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。数据存储形式为键值对,键的类型为字符串型,值的存储数据类型包括数字型、字符型、布尔型以及这3种类型的数组类型。

        在上一篇中,对Preference实例进行封装,实现LocalStorage相关功能,并在基础上再增加对json对象数据存储能力,还实现了数据缓存具有时效性等功能。地址:HarmonyOS开发 - 本地持久化之实现LocalStorage实例-CSDN博客

        不过LocalStorage示例为单例模式,当在多个Ability或多module情况下,不希望所有数据都存储在一个Preferences实例中,这就需要LocalStorage有支持多实例的能力。

一、Ability和Module

        在HarmonyOS开发中,Ability是应用或服务所具备的能力的抽象,它可以响应用户的操作,与用户进行交互。一个Module可以包含一个或多个Ability。HarmonyOS提供了两种应用模式:FA(Feature Ability)模型和Stage模型。

        FA模型从API7开始支持,但已不再是主推的模型。而Stage模型从API 9开始新增,是目前主推且会长期演进的模型。在Stage模型中,Ability分为两种组件类型:

  1. UIAbility组件:包含UI界面,提供展示UI的能力,主要用于和用户交互。
  2. ExtensionAbility组件:提供特定场景的扩展能力,满足更多的使用场景。当前仅OpenHarmony工程支持使用ExtensionAbility组件。

        在HarmonyOS中,应用可以设计为包含多个Ability或者多个module,这取决于应用的复杂性和模块化需求。

1.1 多个Ability

        一个应用可以包含多个Ability,每个Ability代表应用的一种能力。Ability分为Feature Ability(FA)和Particle Ability(PA)两种类型。FA是有UI界面的能力,用于与用户交互,例如一个页面或一个服务。PA是后台运行的能力,可以是Service Ability或Data Ability,用于提供后台任务或数据访问的能力。在Stage模型中,Ability进一步细分为UIAbility组件和ExtensionAbility组件,其中UIAbility组件包含UI界面,而ExtensionAbility组件提供特定场景的扩展能力。

多个Ability

1.2 多个module

        在HarmonyOS中,应用可以被分解为多个功能模块,每个模块负责执行特定的功能。这些模块可以是Shared Library、Static Library或Visual Library。Shared Library是HSP(Harmony Shared Package)动态共享包,Static Library是HAR(Harmony Archive)静态共享包。模块化设计提高了代码的可理解性和可复用性,使应用的扩展和维护变得更为简便,同时降低了系统各部分之间的耦合度。

多个Module

1.3 二者选择

        对于多应用的情况,你可以选择使用多个Ability或多个module,这取决于你的应用架构和业务需求。如果应用功能较为独立,且需要在不同应用间共享,那么可能更适合使用多个module。每个module可以包含一个或多个Ability,这样可以在不同的module之间实现功能的解耦和复用。如果应用的功能较为集中,且主要通过不同的页面或服务来提供用户交互,那么使用多个Ability可能更为合适。

        在实际开发中,你可以根据应用的特点和需求,灵活选择使用多个Ability或多个module,或者将两者结合起来,以实现最佳的应用架构和性能。

二、LocalStorage升级

        在前一篇(地址:HarmonyOS开发 - 本地持久化之实现LocalStorage实例-CSDN博客)中封装的LocalStorage类,创建Preferences实例时指定的实例名称用的是Module模块名称(context.abilityInfo.moduleName);在了解Ability和Module关系后,决定将实例名称更新为Ability名称(context.abilityInfo.name)。

2.1 LocalStorage类

        这里将LocalStorageObj文件复制一份,在新文件中增加多实例功能,同时applicationability和Productability的Ability界面和pages页面中,引入的模块地址也需要同步修改为:"../utils/LocalStorageMulti"。

        这里只需要在之前LocalStorage类基础上,增加一个静态变量用于存储键值对的实例,和一个创建实例的静态函数即可。

  • 键值对的存储器(multiPreferences变量):利用Map对象的特性,键(key)为string类型,用于存储ability名称;值(value)为LocalStorge类型,用于存储类的实例对象。
  • 创建实例函数(multiInstance()函数):通过Map对象中has()方法判断该对应的ability界面实例是否存在,不存在则创建并返回创建的LocalStorage实例;若存在则直接返回该键对应的LocalStorage实例。

        示例代码如下:

import common from '@ohos.app.ability.common'
import preferences from '@ohos.data.preferences'
import { isJsonObject } from './utils'// 定义存储值类型
type valueType = string | number | boolean
// 定义json对象存储类型
type dataType = { value: valueType | object, expire: number }/*** 定义LocalStorage类*/
export class LocalStorage {private preference: preferences.Preferences // 用户首选项实例对象// 定义多Preferences实例 存储变量字段private static multiPreferences: Map<string, LocalStorage> = new Map()/*** 创建多实例* @param context*/static multiInstance(context?: common.UIAbilityContext): LocalStorage {const name = context.abilityInfo.name// 如果存在该实例,则直接返回if(LocalStorage.multiPreferences.has(name)) {console.log('testTag context.abilityInfo.name update', name)return LocalStorage.multiPreferences.get(name)}// 如果不存在,则创建实例else {console.log('testTag context.abilityInfo.name create', name)const instance = new LocalStorage()     // 实例LocalStorage对象instance.initial(context)               // 初始化Preferences实例// 存储LocalStorage对象LocalStorage.multiPreferences.set(name, instance)// 返回实例对象return instance}}// 定义初始化函数initial(context: common.UIAbilityContext): void {// 这里将UIAbility中应用上下文的name作用为实例名称,即该项目的ApplicationAbility或ProductAbilitypreferences.getPreferences(context, context.abilityInfo.name).then(preference => {this.preference = preferenceconsole.log('testTag', 'success~')}).catch(e => {console.log('testTag error', e)})}// 略...
}

        注意:initial()函数中须将之前context.abilityinfo.moduleName修改为context.abilityinfo.name。

2.2 Ability中初始化实例

        在两个Ability中,引入LocalStorage模块,并初始化实例。由于multiinstance()为静态函数,通过LocalStorage类直接调用即可。

applicationability组件:

Productability组件:

2.3 page页面中获取实例

        在HarmonyOS中,aboutToAppear是页面生命周期中的一个关键回调,它在创建自定义组件的新实例后,在执行其build()函数之前执行。这个回调允许开发者在组件实例创建后改变状态变量,并这些更改将在后续执行build()函数中生效。

        aboutToAppear的使用场景包括但不限于:

  1. 初始化页面状态变量
  2. 执行数据绑定和事件监听的设置
  3. 执行与页面显示相关的动画或过渡效果

        总的来说,aboutToAppear是HarmonyOS中管理页面生命周期的一个重要工具,它提供了页面显示前执行初始化操作的能力。而且多应用环境中,合理地使用多个Ability或module可以有效地组织和管理复杂的应用结构。

        因此,我们将通过aboutToAppear来获取本Ability界面中的LocalStorage实例对象。

applicationability界面下的pages/index.ets示例代码如下:

import { LocalStorage } from '../utils/LocalStorageMulti'
import common from '@ohos.app.ability.common'
import Want from '@ohos.app.ability.Want'@Entry
@Component
struct Index {@State message: string = ''private localStorage: LocalStorage    // 定义变量,接收本Ability界面下的LocalStorage实例对象aboutToAppear(){// 获取当前上下文的LocalStorage实例对象this.localStorage = LocalStorage.multiInstance(getContext(this) as common.UIAbilityContext)}// 重置内容renderMsg(message: string | number | boolean){this.message = message.toString()}build() {Row() {Column() {Row(){Text(this.message || '-').fontSize(30).fontWeight(FontWeight.Bold)}.width('100%').height('150vp')Row(){// 添加相关操作按钮Button('添加').onClick(() => {const testData = { name: 'Tom', age: 18 };const expireDate = new Date()// 设置为24小时后失效expireDate.setHours(expireDate.getHours() + 24)// 存储数据this.localStorage.put('indexValue', testData, expireDate)this.renderMsg('add:' + JSON.stringify(testData))console.log('testTag add', testData)})Button('读取').onClick(() => {this.localStorage.getValue('indexValue').then(value => {this.renderMsg('get:' +  (null !== value ? JSON.stringify(value) : value))console.log('testTag get', value)}).catch(err => {console.log('testTag error', err)})})Button('删除').onClick(async () => {this.localStorage.remove('indexValue')const value = await this.localStorage.getValue('indexValue')this.renderMsg('delete:' + value)console.log('testTag delete', value)})Button('跳转新页面').onClick(() => {const context = getContext(this) as common.UIAbilityContextconst want: Want = {bundleName: 'com.example.myapplication',abilityName: 'ProductAbility',moduleName: 'application',parameters: {instanceKey: 'product'}}context.startAbility(want)})}.width('100%').justifyContent(FlexAlign.Center)}.width('100%')}.height('100%').alignItems(VerticalAlign.Top)}
}

        对LocalStorage类进行多实例改造后,数据的存储能力依然能正常执行。如下图:

Productability界面下的pages/indexProduct.ets示例代码如下:

import { LocalStorage } from '../utils/LocalStorageMulti'
import common from '@ohos.app.ability.common'
let index = 0@Entry
@Component
struct Index {@State message: string = ''private localStorage: LocalStorage // 定义变量,接收本Ability界面下的LocalStorage实例对象aboutToAppear(){// 获取当前上下文的LocalStorage实例对象this.localStorage = LocalStorage.multiInstance(getContext(this) as common.UIAbilityContext)}// 重置内容renderMsg(message: string | number | boolean){this.message = message.toString()}build() {Row() {Column() {Row(){Text(this.message || '-').fontSize(30).fontWeight(FontWeight.Bold)}.width('100%').height('150vp')Row(){// 添加相关操作按钮Button('添加').onClick(() => {this.localStorage.put('indexValue', ++index)this.renderMsg('add:' + index)console.log('testTag add', index)})Button('读取').onClick(() => {this.localStorage.getValue('indexValue').then(value => {this.renderMsg('get:' +  (null !== value ? JSON.stringify(value) : value))console.log('testTag get', value)}).catch(err => {console.log('testTag error', err)})})Button('删除').onClick(async () => {this.localStorage.remove('indexValue')const value = await this.localStorage.getValue('indexValue')this.renderMsg('delete:' + value)console.log('testTag delete', value)})}.width('100%').justifyContent(FlexAlign.Center)}.width('100%')}.height('100%').alignItems(VerticalAlign.Top)}
}

        在Applicationability界面点击添加和读取后,再跳转到Productability界面,点击“读取”按钮,看是否能获取到Applicationability界面的indexValue键对应的值。如下图,显示是获取不到的,虽然两则都存的键为indexValue,但都存储在不能的Preferences实例中。

        在Productability界面,点击添加后,再读取。结果如下图:

2.4 multiInstance()函数

        在LocalStorage实现多实例功能时,对multiInstance()函数的设计,是可以无须先初始化实例,直接在页面中aboutToAppear回调函数并获取当前Ability界面实例。

        此时我们将两个Ability中的onCreate()函数,执行的LocalStorage.multiInstance()删除掉,只在page页面直接获取,再看下结果。

        如上图,初始化实例调用的函数注释掉后,结果是怎样的。

        如上图,此时只执行了页面中的multiInstance()函数,但操作结果依然是正常的;不过注意的是,在aboutToAppear回调函数中只是初始化LocalStorage实例是没问题的,但是直接调用实例对象的put()、get()、remove()、clear()等函数,可能会报错,显示preference实例不在存,这是因为initial()函数中是通过Promise异步回调获取的preference实例的。

        所以,是否需要在ability中执行初始化,还是在页面中执行初始化,根据实现需求而定。

2.5 总结

        在多应用的环境中,你可能会使用多个Ability或多个module来组织你的应用。Ability允许你创建多个具有不同功能的页面或服务,而module则允许你将应用分解为多个功能模块,每个模块可以包含一个或多个Ability。这样的设计有助于提高代码的可维护性和可扩展性。

        该篇是为上一篇(HarmonyOS开发 - 本地持久化之实现LocalStorage实例-CSDN博客)的补充内容,希望对大家有所帮助。


http://www.ppmy.cn/news/1542339.html

相关文章

UnityShader——基础篇之学习Shader所需的数学基础——下

裁剪空间 顶点接下来要从观察空间转换到裁剪空间&#xff08;也被称为齐次裁剪空间&#xff09; 中&#xff0c;这个用于变换的矩阵叫做裁剪矩阵&#xff0c;也被称为投影矩阵 裁剪空间的目标是能够方便地对渲染图元进行裁剪&#xff1a;完全位于这块空间内部的图元将会被保留&…

CF-Loss:用于视网膜多分类血管分割和血管特征测量的临床相关特征优化损失函数|文献速递-基于生成模型的数据增强与疾病监测应用

Title 题目 CF-Loss: Clinically-relevant feature optimised loss function for retinal multi-class vessel segmentation and vascular feature measurement CF-Loss&#xff1a;用于视网膜多分类血管分割和血管特征测量的临床相关特征优化损失函数 01 文献速递介绍 视…

HarmonyOS 相对布局(RelativeContainer)

1. HarmonyOS 相对布局&#xff08;RelativeContainer&#xff09; 文档中心:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-layout-development-relative-layout-V5   RelativeContainer为采用相对布局的容器&#xff0c;支持容器内部的子元素设…

Flutter鸿蒙next 中如何实现 WebView【跳、显、适、反】等一些基础问题

✅近期推荐&#xff1a;求职神器 https://bbs.csdn.net/topics/619384540 &#x1f525;欢迎大家订阅系列专栏&#xff1a;flutter_鸿蒙next &#x1f4ac;淼学派语录&#xff1a;只有不断的否认自己和肯定自己&#xff0c;才能走出弯曲不平的泥泞路&#xff0c;因为平坦的大路…

栈与队列(概念与实现)

目录 前言 一&#xff0c;栈 1&#xff0c;栈&#xff08;Stack&#xff09; 2&#xff0c;栈的实现 3&#xff0c;栈的用途 二&#xff0c;队列 1&#xff0c;队列&#xff08;Queue&#xff09; 2&#xff0c;队列的实现 3&#xff0c;队列的用途 4&#xff0c;环形…

ElasticSearch基础概念

基础概念 elasticsearch 是面向 文档存储 的&#xff0c;可以是数据库中的一条商品数据&#xff0c;一个订单信息。 文档数据会被序列化为 json 格式后存储在 elasticsearch 中。 索引 类似Mysql中的表 同类型文档的集合 文档 类似于Mysql中的行数据 一条数据就是一个文档…

电脑异常情况总结

文章目录 笔记本无症状息屏黑屏 笔记本无症状息屏黑屏 &#x1f34e; 问题描述&#xff1a; 息屏导致黑屏&#xff1b;依次操作计算机--》右键--》管理--》事件查看器--》Windows日志--》系统&#xff1b;从息屏到异常黑屏之间出现了很多错误&#xff0c;如下&#xff1a;事件…

电商平台数据分析:从商品数据收集到挖掘的完整流程

随着互联网技术的不断进步和普及&#xff0c;电商平台得到了迅猛的发展。然而&#xff0c;在众多的电商竞争中&#xff0c;如何进行有效的商品数据分析&#xff0c;提高用户体验&#xff0c;优化库存管理&#xff0c;是每一个电商平台都必须要面对的挑战。本文将详细介绍电商平…