一、概述
应用数据持久化,是指应用将内存中的数据通过文件或数据库的形式保存到设备上。内存中的数据形态通常是任意的数据结构或数据对象,存储介质上的数据形态可能是文本、数据库、二进制文件等。
持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等。
HarmonyOS标准系统支持典型的存储数据形态,包括用户首选项、键值型数据库、关系型数据库。
- 用户首选项(Preferences):通常用于保存应用的配置信息。数据通过文本的形式保存在设备中,应用使用过程中会将文本中的数据全量加载到内存中,所以访问速度快、效率高,但不适合需要存储大量数据的场景。
- 键值型数据库(KV-Store):一种非关系型数据库,其数据以“键值”对的形式进行组织、索引和存储,其中“键”作为唯一标识符。适合很少数据关系和业务关系的业务数据存储,同时因其在分布式场景中降低了解决数据库版本兼容问题的复杂度,和数据同步过程中冲突解决的复杂度而被广泛使用。相比于关系型数据库,更容易做到跨设备跨版本兼容。
- 关系型数据库(RelationalStore):一种关系型数据库,以行和列的形式存储数据,广泛用于应用中的关系型数据的处理,包括一系列的增、删、改、查等接口,开发者也可以运行自己定义的SQL语句来满足复杂业务场景的需要。
二 、用户首选项
用户首选项(Perference)为应用提供 key-value 键值型的数据处理能力,支持应用持久化轻量级数据
说白了,用户首选项就是用来保存和记录用户在操作应用的过程做做出的一些选择或设置。 可以存储一些数据,但基本都是简单类型的数据,主要作用都是存储一些用户设置数据,比如是否是首次登陆,就可以设置一个布尔类型的变量,设值为true或false。
你可以粗暴的将它看作类似于redis的以键值对存储的本地非关系型数据库(NoSql),这样方便你使用与理解。
再或者你可以将它想象成一个用来存储数据的仓库/中转站,可以跨组件的使用这些数据
约束限制
- Key键为string类型,要求非空且长度不超过80个字节。
- 如果Value值为string类型,可以为空,不为空时长度不超过8192个字节。
- 内存会随着存储数据量的增大而增大,所以存储的数据量应该是轻量级的,建议存储的数据不超过一万条,否则会在内存方面产生较大的开销。
使用步骤
1、导入用户首选项模块
import preferences from '@ohos.data.preferences'
2、获取Perferences实例,读取指定文件
preference.getPreferences(this.context,"MyAppPreferences").then(preferences => {//获取成功}).catch(reason => {//获取失败})
3、 数据操作
//写入数据,如果已经存在则会覆盖,可以利用.has()判断是否存在
preferences.put('key',val).then(() => {preferences.flush() //刷到磁盘中}).catch(reason => {}) //处理异常//删除数据
preferences.delete('key').then(() => {}).catch(reason => {})//查询数据,defaultValue是默认值,没有值时就返回这个
preferences.get('key','defaultValue').then(value => {}).catch(reason => {})
封装工具类
我们可以将这些功能封装成一个工具类
import preferences from '@ohos.data.preferences'class PreferencesUtil {//map集合存储多个不同的preferencepreferencesMap: Map<string, preferences.Preferences> = new Map;//加载一个preferenceloadPreference(context, name: string) {//返回值是一个Promise包裹起来的preference,因此可以使用链式回调函数处理preferences.getPreferences(context, name).then(preference => {this.preferencesMap.set(name, preference)console.log('testTag', `加载Preference [${name}]成功`);}).catch(reason => {console.log('testTag', `加载Preference [${name}]失败`, JSON.stringify(reason));})}//获取指定preference并存入键值对数据async putPreferenceValue(name: string, key: string, value: preferences.ValueType) {if (!this.preferencesMap.has(name)) {console.log('testTag', `Preference[${name}]尚未初始化`);//结束异步return}try {let preference = this.preferencesMap.get(name)//写入数据await preference.put(key, value)//刷新磁盘preference.flush()console.log('testTag', `保存Preferences[${name}:${key}=${value}]成功`)} catch (e) {console.log('testTag', `保存Preferences[${name}.${key}=${value}]失败`, JSON.stringify(e));}}//获取指定preference的指定数据async getPreferenceValue(name: string, key: string, defaultValue: preferences.ValueType) {if (!this.preferencesMap.has(name)) {console.log('testTag', `Preference[${name}]尚未初始化`);//结束异步return}try {let preference = this.preferencesMap.get(name)//读数据let value = await preference.get(key, defaultValue)console.log('testTag', `获取Preferences[${name}:${key}=${value}]成功`)return value} catch (e) {console.log('testTag', `获取Preferences[${name}.${key}]失败`, JSON.stringify(e));}}//删除指定preference的指定数据async deletePreferenceValue(name: string, key: string, defaultValue: preferences.ValueType) {return isPreferencesHas(this.preferencesMap, name);try {let preference = this.preferencesMap.get(name)//删除数据preference.delete(key)console.log('testTag', `删除Preferences[${name}.${key}]成功`)} catch (err) {console.log('testTag', `删除Preferences[${name}.${key}]失败`)}}
}const isPreferencesHas = function (preferenceMap: Map<string, preferences.Preferences>, name) {if (!this.preferencesMap.has(name)) {console.log('testTag', `Preference[${name}]尚未初始化`);//结束异步return}
}const preferencesUtil = new PreferencesUtil()export default preferencesUtil as PreferencesUtil
示例
在使用preferences之前肯定要先加载一个preference实例,然后才能使用接下来的增删查功能。
既然要加载,肯定不能是像之前那样让用户点个按钮触发创建,而是最好程序已启动就自动隐式的创建,所以使用生命周期的钩子函数onCreate()方法(其实就相当于Vue的onMount()钩子函数)
在EntryAbility文件中调用加载preference即可