当前位置: 首页 > article >正文

HarmonyOS NEXT:保存应用数据

用户首选项使用

用户首选项的特点

数据体积小、访问频率高、有加载速度要求的数据如用户偏好设置、用户字体大小、应用的配置参数。

用户搜选项(Preferences)提供了轻量级配置数据的持久化能力,支持订阅数据变化的通知能力。不支持分布式同步。

基于Key-Value的数据结构,Key是不重复的关键字,Value是数据值。

Preferences是一种非关系型数据库,不遵循数据库的ACID特性,数据见毫无关系。

用户首选项存储在内存中,存储数据量过大会导致应用占用内存过多。如果需要持久化存储,可以调用Flush接口。

不支持数据加密。

用户首选项使用场景

应用配置参数、用户偏好设置,如应用字体大小个性化调整、主题颜色等。

用户首选项机制原理

用户首选项实际通过持久化文件的形式存储在应用沙箱目录中,ArkTS提供交互接口。每个持久化文件唯一关联一个实例。

用户程序通过UIAbilityContext来获得Preferences实例。 因为一个程序可以有多个UIAbility,所以可以获得多个Preferences实例。

用户首选项主要API

preferences.getPreferencesSync10+

getPreferencesSync(context: Context, options: Options): Preferences

获取Preferences实例,此为同步接口。

参数:

参数名类型必填说明
contextContext

应用上下文。

FA模型的应用Context定义见Context。

Stage模型的应用Context定义见Context。

optionsOptions与Preferences实例相关的配置选项。

返回值:

类型说明
Preferences返回Preferences实例。

示例代码: 

import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';

let dataPreferences: preferences.Preferences | null = null;

class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage) {
    let options: preferences.Options = { name: 'myStore' };
    dataPreferences = preferences.getPreferencesSync(this.context, options);
  }
}
putSync10+

putSync(key: string, value: ValueType): void

将数据写入缓存的Preferences实例中,可通过flush将Preferences实例持久化,此为同步接口。

参数:

参数名类型必填说明
keystring要修改的存储的Key,不能为空。
valueValueType存储的新值。

示例代码: 

dataPreferences.putSync('startup', 'auto');
// 当字符串有特殊字符时,需要将字符串转为Uint8Array类型再存储
let uInt8Array1 = new util.TextEncoder().encodeInto("~!@#¥%……&*()——+?");
dataPreferences.putSync('uInt8', uInt8Array1);
hasSync10+

hasSync(key: string): boolean

检查缓存的Preferences实例中是否包含名为给定Key的存储键值对,此为同步接口。

参数:

参数名类型必填说明
keystring要检查的存储key名称,不能为空。

返回值:

类型说明
boolean返回Preferences实例是否包含给定key的存储键值对,true表示存在,false表示不存在。

示例代码: 

let isExist: boolean = dataPreferences.hasSync('startup');
if (isExist) {
  console.info("The key 'startup' is contained.");
} else {
  console.info("The key 'startup' dose not contain.");
}
getSync10+

getSync(key: string, defValue: ValueType): ValueType

从缓存的Preferences实例中获取键对应的值,如果值为null或者非默认值类型,返回默认数据defValue,此为同步接口。

参数:

参数名类型必填说明
keystring要获取的存储Key名称,不能为空。
defValueValueType默认返回值。

返回值:

类型说明
ValueType返回键对应的值。

示例代码: 

let value: preferences.ValueType = dataPreferences.getSync('startup', 'default');
deleteSync10+

deleteSync(key: string): void

从缓存的Preferences实例中删除名为给定Key的存储键值对,可通过flush将Preferences实例持久化,此为同步接口。

参数:

参数名类型必填说明
keystring要删除的存储key名称,不能为空。

示例代码: 

dataPreferences.deleteSync('startup');
flush

flush(callback: AsyncCallback<void>): void

将缓存的Preferences实例中的数据异步存储到用户首选项的持久化文件中,使用callback异步回调。

参数:

参数名类型必填说明
callbackAsyncCallback<void>

示例代码: 

import { BusinessError } from '@kit.BasicServicesKit';

dataPreferences.flush((err: BusinessError) => {
  if (err) {
    console.error("Failed to flush. code =" + err.code + ", message =" + err.message);
    return;
  }
  console.info("Succeeded in flushing.");
})
let promise = dataPreferences.flush();
promise.then(() => {
  console.info("Succeeded in flushing.");
}).catch((err: BusinessError) => {
  console.error("Failed to flush. code =" + err.code + ", message =" + err.message);
})
on('change')

on(type: 'change', callback: Callback<string>): void

订阅数据变更,订阅的Key的值发生变更后,在执行flush方法后,触发callback回调。

当调用removePreferencesFromCache或者deletePreferences后,订阅的数据变更会主动取消订阅,在重新getPreferences后需要重新订阅数据变更。

参数:

参数名类型必填说明
typestring事件类型,固定值'change',表示数据变更。
callbackCallback<string>回调函数。

示例代码:

let observer = (key: string) => {
  console.info('The key' + key + 'changed.');
}
dataPreferences.on('change', observer);
// 数据产生变更,由'auto'变为'manual'
dataPreferences.put('startup', 'manual', (err: BusinessError) => {
  if (err) {
    console.error(`Failed to put the value of 'startup'. Code:${err.code},message:${err.message}`);
    return;
  }
  console.info("Succeeded in putting the value of 'startup'.");
  if (dataPreferences !== null) {
    dataPreferences.flush((err: BusinessError) => {
      if (err) {
        console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
        return;
      }
      console.info('Succeeded in flushing.');
    })
  }
})
on('dataChange')12+

on(type: 'dataChange', keys: Array<string>, callback: Callback<Record<string, ValueType>>): void

精确订阅数据变更,只有被订阅的key值发生变更后,在执行flush方法后,触发callback回调。

参数:

参数名类型必填说明
typestring事件类型,固定值'dataChange',表示精确的数据变更。
keysArray<string>需要订阅的key集合。
callbackCallback<Record<string, ValueType>>回调函数。回调支持返回多个键值对,其中键为发生变更的订阅key,值为变更后的数据:支持number、string、boolean、Array<number>、Array<string>、Array<boolean>、Uint8Array、object类型。
import { BusinessError } from '@kit.BasicServicesKit';

let observer = (data: Record<string, preferences.ValueType>) => {
  for (const keyValue of Object.entries(data)) {
    console.info(`observer : ${keyValue}`)
  }
  console.info("The observer called.")
}
let keys = ['name', 'age']
dataPreferences.on('dataChange', keys, observer);
dataPreferences.putSync('name', 'xiaohong');
dataPreferences.putSync('weight', 125);
dataPreferences.flush((err: BusinessError) => {
  if (err) {
    console.error("Failed to flush. Cause: " + err);
    return;
  }
  console.info("Succeeded in flushing.");
})
off('change')

off(type: 'change', callback?: Callback<string>): void

取消订阅数据变更。

参数:

参数名类型必填说明
typestring事件类型,固定值'change',表示数据变更。
callbackCallback<string>

示例代码:

import { BusinessError } from '@kit.BasicServicesKit';

let observer = (key: string) => {
  console.info("The key " + key + " changed.");
}
dataPreferences.on('change', observer);
dataPreferences.putSync('startup', 'auto');
dataPreferences.flush((err: BusinessError) => {
  if (err) {
    console.error("Failed to flush. Cause: " + err);
    return;
  }
  console.info("Succeeded in flushing.");
})
dataPreferences.off('change', observer);
preferences.deletePreferences10+

deletePreferences(context: Context, options: Options, callback: AsyncCallback<void>): void

从缓存中移出指定的Preferences实例,若Preferences实例有对应的持久化文件,则同时删除其持久化文件。使用callback异步回调。

调用该接口后,不建议再使用旧的Preferences实例进行数据操作,否则会出现数据一致性问题,应将Preferences实例置为null,系统将会统一回收。

不支持该接口与preference其他接口并发调用。

参数:

参数名类型必填说明
contextContext

应用上下文。

FA模型的应用Context定义见Context。

Stage模型的应用Context定义见Context。

optionsOptions与Preferences实例相关的配置选项。
callbackAsyncCallback<void>回调函数。当移除成功,err为undefined,否则为错误对象。

示例代码:

import { UIAbility } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { window } from '@kit.ArkUI';

class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage) {
    let options: preferences.Options = { name: 'myStore' };
    preferences.deletePreferences(this.context, options, (err: BusinessError) => {
      if (err) {
        console.error("Failed to delete preferences. code =" + err.code + ", message =" + err.message);
        return;
      }
      console.info("Succeeded in deleting preferences.");
    })
  }
}

 用户首选项开发流程

 1. 导入模块

import { preferences } from '@kit.ArkData';

2. 获取preferences实例

import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';

let dataPreferences: preferences.Preferences | null = null;

class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage) {
    let options: preferences.Options = { name: 'myStore' };
    dataPreferences = preferences.getPreferencesSync(this.context, options);
  }
}

3. 保存数据

dataPreferences.putSync('startup', 'auto');

4. 读取数据

dataPreferences.getSync('startup', 'default');

5. 数据持久化

import { BusinessError } from '@kit.BasicServicesKit';

dataPreferences.flush((err: BusinessError) => {
  if (err) {
    console.error("Failed to flush. code =" + err.code + ", message =" + err.message);
    return;
  }
  console.info("Succeeded in flushing.");
})

用户首选项开发实践

用户首选项开发实践文档华为开发者学堂https://developer.huawei.com/consumer/cn/training/course/slightMooc/C101717498132814493

关系型数据库使用 

关系型数据库简介

关系型数据库基于SQLite组件,适用于存储包含复杂关系数据的场景。关系型数据库对应用提供通用的操作接口,底层使用SQLite作为持久化存储引擎,支持SQLite具有的数据库特性,包括但不限于事务、索引、视图、触发器、外键、参数化查询和预编译SQL语句。

 关系型数据库主要API

relationalStore.getRdbStore

getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback<RdbStore>): void

获得一个相关的RdbStore,操作关系型数据库,用户可以根据自己的需求配置RdbStore的参数,然后通过RdbStore调用相关接口可以执行相关的数据操作,使用callback异步回调。

当用非加密方式打开一个已有的加密数据库时,会返回错误码14800011,表示数据库损坏。此时用加密方式可以正常打开该数据库。

getRdbStore目前不支持多线程并发操作。

参数:

参数名类型必填说明
contextContext

应用的上下文。

FA模型的应用Context定义见Context。

Stage模型的应用Context定义见Context。

configStoreConfig与此RDB存储相关的数据库配置。
callbackAsyncCallback<RdbStore>指定callback回调函数,返回RdbStore对象。
示例代码:
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

let store: relationalStore.RdbStore | undefined = undefined;

class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage) {
    const STORE_CONFIG: relationalStore.StoreConfig = {
      name: "RdbTest.db",
      securityLevel: relationalStore.SecurityLevel.S1
    };
        
    relationalStore.getRdbStore(this.context, STORE_CONFIG, (err: BusinessError, rdbStore: relationalStore.RdbStore) => {
      store = rdbStore;
      if (err) {
        console.error(`Get RdbStore failed, code is ${err.code},message is ${err.message}`);
        return;
      }
      console.info('Get RdbStore successfully.');
    })
  }
}
executeSql10+

executeSql(sql: string, callback: AsyncCallback<void>):void

执行包含指定参数但不返回值的SQL语句,语句中的各种表达式和操作符之间的关系操作符号不超过1000个,使用callback异步回调。

此接口不支持执行查询、附加数据库和事务操作,可以使用querySql、query、attach、beginTransaction、commit等接口代替。

不支持分号分隔的多条语句。

参数:

参数名类型必填说明
sqlstring指定要执行的SQL语句。
callbackAsyncCallback<void>指定callback回调函数。

示例代码:

const SQL_DELETE_TABLE = "DELETE FROM test WHERE name = 'zhangsan'"

if(store != undefined) {
  (store as relationalStore.RdbStore).executeSql(SQL_DELETE_TABLE, (err) => {
    if (err) {
      console.error(`ExecuteSql failed, code is ${err.code},message is ${err.message}`);
      return;
    }
    console.info('Delete table done.');
  })
}
insert

insert(table: string, values: ValuesBucket, callback: AsyncCallback<number>):void

向目标表中插入一行数据,使用callback异步回调。由于共享内存大小限制为2Mb,因此单条数据的大小需小于2Mb,否则会查询失败。

参数:

参数名类型必填说明
tablestring指定的目标表名。
valuesValuesBucket表示要插入到表中的数据行。
callbackAsyncCallback<number>指定callback回调函数。如果操作成功,返回行ID;否则返回-1。

 示例代码:

let value1 = "Lisa";
let value2 = 18;
let value3 = 100.5;
let value4 = new Uint8Array([1, 2, 3, 4, 5]);

// 以下三种方式可用
const valueBucket1: relationalStore.ValuesBucket = {
  'NAME': value1,
  'AGE': value2,
  'SALARY': value3,
  'CODES': value4,
};
const valueBucket2: relationalStore.ValuesBucket = {
  NAME: value1,
  AGE: value2,
  SALARY: value3,
  CODES: value4,
};
const valueBucket3: relationalStore.ValuesBucket = {
  "NAME": value1,
  "AGE": value2,
  "SALARY": value3,
  "CODES": value4,
};

if(store != undefined) {
  (store as relationalStore.RdbStore).insert("EMPLOYEE", valueBucket1, (err: BusinessError, rowId: number) => {
    if (err) {
      console.error(`Insert is failed, code is ${err.code},message is ${err.message}`);
      return;
    }
    console.info(`Insert is successful, rowId = ${rowId}`);
  })
}
update

update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback<number>):void

根据RdbPredicates的指定实例对象更新数据库中的数据,使用callback异步回调。由于共享内存大小限制为2Mb,因此单条数据的大小需小于2Mb,否则会查询失败。

参数:

参数名类型必填说明
valuesValuesBucketvalues指示数据库中要更新的数据行。键值对与数据库表的列名相关联。
predicatesRdbPredicatesRdbPredicates的实例对象指定的更新条件。
callbackAsyncCallback<number>指定的callback回调方法。返回受影响的行数。

 示例代码:

let value1 = "Rose";
let value2 = 22;
let value3 = 200.5;
let value4 = new Uint8Array([1, 2, 3, 4, 5]);

// 以下三种方式可用
const valueBucket1: relationalStore.ValuesBucket = {
  'NAME': value1,
  'AGE': value2,
  'SALARY': value3,
  'CODES': value4,
};
const valueBucket2: relationalStore.ValuesBucket = {
  NAME: value1,
  AGE: value2,
  SALARY: value3,
  CODES: value4,
};
const valueBucket3: relationalStore.ValuesBucket = {
  "NAME": value1,
  "AGE": value2,
  "SALARY": value3,
  "CODES": value4,
};

let predicates = new relationalStore.RdbPredicates("EMPLOYEE");
predicates.equalTo("NAME", "Lisa");
if(store != undefined) {
  (store as relationalStore.RdbStore).update(valueBucket1, predicates,(err, rows) => {
    if (err) {
      console.error(`Updated failed, code is ${err.code},message is ${err.message}`);
      return;
    }
    console.info(`Updated row count: ${rows}`);
  })
}

delete

delete(predicates: RdbPredicates, callback: AsyncCallback<number>):void

根据RdbPredicates的指定实例对象从数据库中删除数据,使用callback异步回调。

参数:

参数名类型必填说明
predicatesRdbPredicatesRdbPredicates的实例对象指定的删除条件。
callbackAsyncCallback<number>指定callback回调函数。返回受影响的行数。

 示例代码:

let predicates = new relationalStore.RdbPredicates("EMPLOYEE");
predicates.equalTo("NAME", "Lisa");
if(store != undefined) {
  (store as relationalStore.RdbStore).delete(predicates, (err, rows) => {
    if (err) {
      console.error(`Delete failed, code is ${err.code},message is ${err.message}`);
      return;
    }
    console.info(`Delete rows: ${rows}`);
  })
}
query10+

query(predicates: RdbPredicates, callback: AsyncCallback<ResultSet>):void

根据指定条件查询数据库中的数据,使用callback异步回调。由于共享内存大小限制为2Mb,因此单条数据的大小需小于2Mb,否则会查询失败。

参数:

参数名类型必填说明
predicatesRdbPredicatesRdbPredicates的实例对象指定的查询条件。
callbackAsyncCallback<ResultSet>指定callback回调函数。如果操作成功,则返回ResultSet对象。
let predicates = new relationalStore.RdbPredicates("EMPLOYEE");
predicates.equalTo("NAME", "Rose");
if(store != undefined) {
  (store as relationalStore.RdbStore).query(predicates, (err, resultSet) => {
    if (err) {
      console.error(`Query failed, code is ${err.code},message is ${err.message}`);
      return;
    }
    console.info(`ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}`);
    // resultSet是一个数据集合的游标,默认指向第-1个记录,有效的数据从0开始。
    while (resultSet.goToNextRow()) {
      const id = resultSet.getLong(resultSet.getColumnIndex("ID"));
      const name = resultSet.getString(resultSet.getColumnIndex("NAME"));
      const age = resultSet.getLong(resultSet.getColumnIndex("AGE"));
      const salary = resultSet.getDouble(resultSet.getColumnIndex("SALARY"));
      console.info(`id=${id}, name=${name}, age=${age}, salary=${salary}`);
    }
    // 释放数据集的内存,若不释放可能会引起fd泄露与内存泄露
    resultSet.close();
  })
}
relationalStore.deleteRdbStore10+

deleteRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback<void>): void

使用指定的数据库文件配置删除数据库,使用callback异步回调。

删除成功后,建议将数据库对象置为null。若数据库文件处于公共沙箱目录下,则删除数据库时必须使用该接口,当存在多个进程操作同一个数据库的情况,建议向其他进程发送数据库删除通知使其感知并处理。建立数据库时,若在StoreConfig中配置了自定义路径,则必须调用此接口进行删库。 

参数:

参数名类型必填说明
contextContext

应用的上下文。

FA模型的应用Context定义见Context。

Stage模型的应用Context定义见Context。

configStoreConfig与此RDB存储相关的数据库配置。
callbackAsyncCallback<void>指定callback回调函数。

示例代码:

import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

let store: relationalStore.RdbStore | undefined = undefined;

class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage){
    const STORE_CONFIG: relationalStore.StoreConfig = {
      name: "RdbTest.db",
      securityLevel: relationalStore.SecurityLevel.S1
    };
    relationalStore.deleteRdbStore(this.context, STORE_CONFIG, (err: BusinessError) => {
      if (err) {
        console.error(`Delete RdbStore failed, code is ${err.code},message is ${err.message}`);
        return;
      }
      store = undefined;
      console.info('Delete RdbStore successfully.');
    })
  }
}
备份数据库
if (store !== undefined) {
  // "Backup.db"为备份数据库文件名,默认在RdbStore同路径下备份。也可指定路径:customDir + "backup.db"
  (store as relationalStore.RdbStore).backup("Backup.db", (err: BusinessError) => {
    if (err) {
      console.error(`Failed to backup RdbStore. Code:${err.code}, message:${err.message}`);
      return;
    }
    console.info(`Succeeded in backing up RdbStore.`);
  })
}
从备份数据库中恢复数据
if (store !== undefined) {
  (store as relationalStore.RdbStore).restore("Backup.db", (err: BusinessError) => {
    if (err) {
      console.error(`Failed to restore RdbStore. Code:${err.code}, message:${err.message}`);
      return;
    }
    console.info(`Succeeded in restoring RdbStore.`);
  })
}

关系型数据库开发实践 

关系型数据库开发实践华为开发者学堂https://developer.huawei.com/consumer/cn/training/course/slightMooc/C101717498132814493 


http://www.kler.cn/a/530136.html

相关文章:

  • 计算机网络 应用层 笔记1(C/S模型,P2P模型,FTP协议)
  • 探索 Copilot:开启智能助手新时代
  • 人工智能学习(四)之机器学习基本概念
  • [原创](Modern C++)现代C++的关键性概念: 流格式化
  • Docker 部署 GLPI(IT 资产管理软件系统)
  • 51单片机入门_01_单片机(MCU)概述(使用STC89C52芯片;使用到的硬件及课程安排)
  • 消息队列应用示例MessageQueues-STM32CubeMX-FreeRTOS《嵌入式系统设计》P343-P347
  • vector容器(详解)
  • 【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.3 结构化索引:记录数组与字段访问
  • ExternalName Service 针对的是k8s集群外部有api服务的场景?
  • Haskell语言的多线程编程
  • [权限提升] Windows 提权 维持 — 系统错误配置提权 - Trusted Service Paths 提权
  • IM 即时通讯系统-43-简单的仿QQ聊天安卓APP
  • 2024 年 6 月大学英语四级考试真题(第 3 套)——纯享题目版
  • linux本地部署deepseek-R1模型
  • 内部知识库助力组织智力激发与信息共享实现业绩增长
  • 《手札·开源篇》从开源到商业化:中小企业的低成本数字化转型路径 ——以Odoo为数据中台低成本实现售前售中一体化
  • [Java]异常
  • GAMES101学习笔记(六):Geometry 几何(基本表示方法、曲线与曲面、网格处理)
  • 海外问卷调查渠道查,如何影响企业的运营
  • Rust 变量特性:不可变、和常量的区别、 Shadowing
  • 零基础学习书生.浦语大模型-入门岛
  • IM 即时通讯系统-50-[特殊字符]cim(cross IM) 适用于开发者的分布式即时通讯系统
  • 封装常用控制器
  • Java NIO全面详解
  • FreeRTOS学习 --- 消息队列