鸿蒙数据持久化之首选项

场景介绍

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

运作机制

如图所示,用户程序通过ArkTS接口调用用户首选项读写对应的数据文件。开发者可以将用户首选项持久化文件的内容加载到Preferences实例,每个文件唯一对应到一个Preferences实例,系统会通过静态容器将该实例存储在内存中,直到主动从内存中移除该实例或者删除该文件。

应用首选项的持久化文件保存在应用沙箱内部,可以通过context获取其路径。具体可见获取应用文件路径。

图1 用户首选项运作机制

img

约束限制

  • 首选项无法保证进程并发安全,会有文件损坏和数据丢失的风险,不支持在多进程场景下使用。

  • Key键为string类型,要求非空且长度不超过1024个字节。

  • 如果Value值为string类型,请使用UTF-8编码格式,可以为空,不为空时长度不超过16 * 1024 * 1024个字节。

  • 内存会随着存储数据量的增大而增大,所以存储的数据量应该是轻量级的,建议存储的数据不超过一万条,否则会在内存方面产生较大的开销。

接口说明

以下是用户首选项持久化功能的相关接口,更多接口及使用方式请见用户首选项。

接口名称描述
getPreferencesSync(context: Context, options: Options): Preferences获取Preferences实例。该接口存在异步接口。
putSync(key: string, value: ValueType): void将数据写入Preferences实例,可通过flush将Preferences实例持久化。该接口存在异步接口。
hasSync(key: string): boolean检查Preferences实例是否包含名为给定Key的存储键值对。给定的Key值不能为空。该接口存在异步接口。
getSync(key: string, defValue: ValueType): ValueType获取键对应的值,如果值为null或者非默认值类型,返回默认数据defValue。该接口存在异步接口。
deleteSync(key: string): void从Preferences实例中删除名为给定Key的存储键值对。该接口存在异步接口。
flush(callback: AsyncCallback<void>): void将当前Preferences实例的数据异步存储到用户首选项持久化文件中。
on(type: 'change', callback: Callback<string>): void订阅数据变更,订阅的数据发生变更后,在执行flush方法后,触发callback回调。
off(type: 'change', callback?: Callback<string>): void取消订阅数据变更。
deletePreferences(context: Context, options: Options, callback: AsyncCallback<void>): void从内存中移除指定的Preferences实例。若Preferences实例有对应的持久化文件,则同时删除其持久化文件。

开发步骤

新增/修改数据

image.png

import { preferences } from '@kit.ArkData'
​
@Entry
@Component
struct Index {build() {Row() {Column() {// 1.0 利用首选项api对store这个文件做一个新增数据:["鸿蒙","HTML5"]Button('新增/修改数据').onClick(() => {//   1.0 获取store文件的操作对象const pre = preferences.getPreferencesSync(getContext(), { name: 'store' })
​//   2.0 调用操作对象上的putSync方法完成数据的新增 (这是将数据保存到内存中)pre.putSync('keyword', ["鸿蒙Next", "huawei"])pre.putSync('keyword2', ["HTML5", "JavaScript"])
​pre.flush() //将内存数据写入到磁盘
​AlertDialog.show({ message: '首选项数据写入成功' })})}.width('100%')}
​}
}

 

结果查询:

修改数据就还是用key值把之前数据修改成需要的就行

查询数据

image.png

代码:

Button('获取数据').onClick(() => {const pre = preferences.getPreferencesSync(getContext(), { name: 'store' })AlertDialog.show({ message: JSON.stringify(pre.getAllSync()) })
})

删除数据

image.png

Button('删除数据').onClick(() => {const pre = preferences.getPreferencesSync(getContext(), { name: 'store' })pre.deleteSync('keyword')pre.flush()AlertDialog.show({ message: '首选项数据删除成功' })})

实例

通过一个搜索框实例进行系统组合起来

静态结构

@Entry
@Component
struct SearchPage {@State keyword: string = ''@State isdel: boolean = falseaboutToAppear(): void {
​}
​@BuilderitemBuilder(text: string) {Row({ space: 20 }) {Text(text)if (this.isdel) {Text('x').height(30).onClick(() => {AlertDialog.show({ message: '删除' + text })})}}.margin({ right: 10, top: 10 }).padding({left: 15,right: 15,top: 5,bottom: 5}).backgroundColor('rgba(0,0,0,0.05)').borderRadius(20)}
​build() {Navigation() {Column({ space: 15 }) {// 1. 搜索关键字TextInput({ placeholder: '输入回车保存数据', text: $$this.keyword }).onSubmit(() => {AlertDialog.show({ message: this.keyword })})
​// 2. 关键字列表Row() {Text('搜索记录').fontSize(20).fontWeight(800)
​Row() {if (this.isdel) {Text('全部删除').onClick(()=>{AlertDialog.show({ message: '补上全部删除逻辑' })})Text(' | ')Text('取消删除').onClick(()=>{this.isdel = false})} else {Text('X').height(28).onClick(()=>{this.isdel = true})}}}.width('100%').justifyContent(FlexAlign.SpaceBetween)
​//   3. 关键字列表Flex({ wrap: FlexWrap.Wrap }) {ForEach([1, 2, 3, 4], (item: number) => {this.itemBuilder('文本' + item)})}}.padding(15)}.padding({ top: 20 }).titleMode(NavigationTitleMode.Mini).title('搜索页面')}
}

实现历史搜索记录

保存关键字数组
import { preferences } from '@kit.ArkData'
​
@Entry
@Component
struct SearchPage {@State keyword: string = ''@State isdel: boolean = false@State keywords: string[] = []aboutToAppear(): void {this.getData()}// 1.0 新增方法async saveData(text: string) {// 非空验证if(!text){return}// 1.0 获取首选项对象实例const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })// 2.0 调用putsync方法保存数组// 2.0.1 先从首选项中获取老数据let dataArr = pre.getSync('keyword', []) as string[]// 判断如果首选项中已经有了该关键词,不再保存if(dataArr.includes(text)){// 该关键字已经存在了,不保存return}
​dataArr.push(text)// 2.0.2 存数据pre.putSync('keyword', dataArr)
​// 3.0 调用flush写入到磁盘await pre.flush()}// 2.0 获取首选项数据async getData() {const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })this.keywords = pre.getSync('keyword', []) as string[]}
​
​@BuilderitemBuilder(text: string) {Row({ space: 20 }) {Text(text)if (this.isdel) {Text('x').height(30).onClick(() => {AlertDialog.show({ message: '删除' + text })})}}.margin({ right: 10, top: 10 }).padding({left: 15,right: 15,top: 5,bottom: 5}).backgroundColor('rgba(0,0,0,0.05)').borderRadius(20)}
​build() {Navigation() {Column({ space: 15 }) {// 1. 搜索关键字TextInput({ placeholder: '输入回车保存数据', text: $$this.keyword }).onSubmit(async () => {
​AlertDialog.show({ message: this.keyword })//   将关键词数据保存到首选项中await  this.saveData(this.keyword)await this.getData()})
​// 2. 关键字列表Row() {Text('搜索记录').fontSize(20).fontWeight(800)
​Row() {if (this.isdel) {Text('全部删除').onClick(()=>{AlertDialog.show({ message: '补上全部删除逻辑' })})Text(' | ')Text('取消删除').onClick(()=>{this.isdel = false})} else {Text('X').height(28).onClick(()=>{this.isdel = true})}}}.width('100%').justifyContent(FlexAlign.SpaceBetween)
​//   3. 关键字列表Flex({ wrap: FlexWrap.Wrap }) {ForEach(this.keywords, (item: string) => {this.itemBuilder(item)})}}.padding(15)}.padding({ top: 20 }).titleMode(NavigationTitleMode.Mini).title('搜索页面')}
}

删除指定关键字/全部关键字
  async delData(text?: string) {const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })//   1.0 删除全部关键if (!text) {pre.deleteSync('keyword')} else {// 2.0 删除指定关键字  获取 -> 删除内存数组的关键字 -> 写回let datas = pre.getSync('keyword', []) as string[]let cindex = datas.findIndex(item => item === text)// 当关键字索引为-1的时候,表示没有找到if (cindex < 0) {return}// 如果有删除datas.splice(cindex, 1) // 返回值表示删除的元素//   保存回去pre.putSync('keyword', datas)}// 写回磁盘pre.flush()}
          //  删除指定关键字await this.delData(text)await this.getData()})
              // 删除全局数据await this.delData()await this.getData()})

完整代码

import { preferences } from '@kit.ArkData'@Entry
@Component
struct SearchPage {@State keyword: string = ''@State isdel: boolean = false@State keywords: string[] = []aboutToAppear(): void {this.getData()}// 1.0 新增方法async saveData(text: string) {// 非空验证if(!text){return}// 1.0 获取首选项对象实例const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })// 2.0 调用putsync方法保存数组// 2.0.1 先从首选项中获取老数据let dataArr = pre.getSync('keyword', []) as string[]// 判断如果首选项中已经有了该关键词,不再保存if(dataArr.includes(text)){// 该关键字已经存在了,不保存return}dataArr.push(text)// 2.0.2 存数据pre.putSync('keyword', dataArr)// 3.0 调用flush写入到磁盘await pre.flush()}// 2.0 获取首选项数据async getData() {const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })this.keywords = pre.getSync('keyword', []) as string[]}// 3.0 删除指定关键字和全部关键字async delData(text?: string) {const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })//   1.0 删除全部关键if (!text) {pre.deleteSync('keyword')} else {// 2.0 删除指定关键字  获取 -> 删除内存数组的关键字 -> 写回let datas = pre.getSync('keyword', []) as string[]let cindex = datas.findIndex(item => item === text)// 当关键字索引为-1的时候,表示没有找到if (cindex < 0) {return}// 如果有删除datas.splice(cindex, 1) // 返回值表示删除的元素//   保存回去pre.putSync('keyword', datas)}// 写回磁盘pre.flush()}@BuilderitemBuilder(text: string) {Row({ space: 20 }) {Text(text)if (this.isdel) {Text('x').height(30).onClick(async () => {//  删除指定关键字await this.delData(text)await this.getData()AlertDialog.show({ message: '删除' + text })})}}.margin({ right: 10, top: 10 }).padding({left: 15,right: 15,top: 5,bottom: 5}).backgroundColor('rgba(0,0,0,0.05)').borderRadius(20)}build() {Navigation() {Column({ space: 15 }) {// 1. 搜索关键字TextInput({ placeholder: '输入回车保存数据', text: $$this.keyword }).onSubmit(async () => {AlertDialog.show({ message: this.keyword })//   将关键词数据保存到首选项中await  this.saveData(this.keyword)await this.getData()})// 2. 关键字列表Row() {Text('搜索记录').fontSize(20).fontWeight(800)Row() {if (this.isdel) {Text('全部删除').onClick(async ()=>{// 删除全局数据await this.delData()await this.getData()})Text(' | ')Text('取消删除').onClick(()=>{this.isdel = false})} else {Text('X').height(28).onClick(()=>{this.isdel = true})}}}.width('100%').justifyContent(FlexAlign.SpaceBetween)//   3. 关键字列表Flex({ wrap: FlexWrap.Wrap }) {ForEach(this.keywords, (item: string) => {this.itemBuilder(item)})}}.padding(15)}.padding({ top: 20 }).titleMode(NavigationTitleMode.Mini).title('搜索页面')}
}

总结

  • 该文档介绍了用户首选项数据持久化的概念、约束和接口,并通过一个搜索页面的实例展示了如何使用用户首选项存储、查询、修改和删除数据。

  • 开发者在使用时需注意数据量的控制和进程安全问题,合理利用接口实现数据的持久化操作,确保应用的正常运行和数据的一致性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/37235.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PyTorch分布式训练中各节点如何通信

深度学习 文章目录 深度学习前言pytorch如何初始化分布式训练怎么知道要使用哪几台机器进行训练的如何根据标识进行初始化&#xff08;init_method&#xff09;如何获取进程的唯一标识rank如何实现数据如何分发 前言 同学们在处理分布式训练时经常会遇到以下几个疑问&#xff…

[数据结构]排序之 归并排序(有详细的递归图解)

一、非递归 基本思想&#xff1a; 归并排序&#xff08; MERGE-SORT &#xff09;是建立在归并操作上的一种有效的排序算法 , 该算法是采用分治法&#xff08; Divide andConquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#x…

在本地跑通spark环境

官网下载spark 下载spark 解压就好 本地配置环境变量 配置环境变量&#xff08;系统环境变量&#xff09; 新增 SPARK_HOME 变量名&#xff1a;SPARK_HOME 变量值&#xff1a;F:\class\spark\Spark_env\spark-3.4.4-bin-hadoop3 配置 PATH&#xff0c;新增如下&#xff1a…

UE5材质法线强度控制节点FlattenNormal

连法 FlattenNormal内部是这样的 FlattenNormal的作用是用来调整法线强度 连上FlattenNormal后 拉高数值

Appium使用文档

Appium旨在支持许多不同平台&#xff08;移动端、网页端、桌面端等&#xff09;的UI自动化。不仅如此&#xff0c;它还旨在支持用不同语言&#xff08;JS、Java、Python等&#xff09;编写的自动化代码。 1. 环境搭建 资源下载&#xff1a; 链接: https://pan.baidu.com/s/1K5Q…

Python绘图技巧,主流绘图库

一、主流绘图库概览 1. 核心工具对比 库名称特点适用场景Matplotlib基础绘图库&#xff0c;高度可定制科学绘图、论文图表Seaborn基于Matplotlib&#xff0c;统计图表优化数据分布、关系可视化Plotly交互式可视化&#xff0c;支持网页输出仪表盘、动态数据展示Pandas内置简易…

使用LLM自动化生成微电网Simulink模型

&#x1f680; 使用LLM自动化生成微电网Simulink模型&#xff01;⚡ 在构建微电网仿真模型时&#xff0c;我们通常需要手动拖拽模块、设置参数&#xff0c;耗费大量时间。现在&#xff0c;通过结合LLM&#xff08;如 GPT-4&#xff09;与 MATLAB 脚本&#xff0c;我们可以自动…

Git常用操作之GitLab

Git常用操作之GitLab 小薛博客官网&#xff1a;小薛博客Git常用操作之GitLab官方地址 1、GitLab安装 https://gitlab.cn/install/ 1、Docker安装GitLab https://docs.gitlab.cn/jh/install/docker.html 1、设置卷位置 在设置其他所有内容之前&#xff0c;请配置一个新的…

【AI】AI编程助手:Cursor、Codeium、GitHub Copilot、Roo Cline、Tabnine

文章目录 一、基本特性对比二、收费标准三、私有部署能力1、Tabnine2、Roo Code 三、代码补全与自然语言生成代码四、安装独立的IDE安装插件安装 五、基本使用&#xff08;一&#xff09;Cursor&#xff08;二&#xff09;GitHub Copilot1、获取代码建议2.聊天1&#xff09;上下…

[贪心算法]买卖股票的最佳时机 买卖股票的最佳时机Ⅱ K次取反后最大化的数组和 按身高排序 优势洗牌(田忌赛马)

1.买卖股票的最佳时机 暴力解法就是两层循环&#xff0c;找出两个差值最大的即可。 优化&#xff1a;在找最小的时候不用每次都循环一遍&#xff0c;只要在i向后走的时候&#xff0c;每次记录一下最小的值即可 class Solution { public:int maxProfit(vector<int>& p…

康谋方案 | AVM合成数据仿真验证方案

随着自动驾驶技术的快速发展&#xff0c;仿真软件在开发过程中扮演着越来越重要的角色。仿真传感器与环境不仅能够加速算法验证&#xff0c;还能在安全可控的条件下进行复杂场景的重复测试。 本文将分享如何利用自动驾驶仿真软件配置仿真传感器与搭建仿真环境&#xff0c;并对…

Django Rest Framework 创建纯净版Django项目部署DRF

描述创建纯净版的Django项目和 Django Rest Framework 环境的部署 一、创建Django项目 1. 环境说明 操作系统 Windows11python版本 3.9.13Django版本 V4.2.202. 操作步骤(在Pycharm中操作) 创建Python项目drfStudy、虚拟环境 ​虚拟环境中安装 jdangopip install django==4.…

数据结构篇——二叉树的存储与遍历

一、引入 书接上文&#xff0c;文于此续。上文我们学到了树的存储结构&#xff0c;那么今天&#xff0c;我们来学习下几种特殊的二叉树以及关于它的各种遍历&#xff0c;让我们一起加油吧。 二、特殊的二叉树 二叉树的特殊形式这里介绍3种&#xff0c;其中需要着重记忆的有…

Vulnhub-wordpress通关攻略

姿势一、后台修改模板拿WebShell 第一步&#xff1a;进⼊Vulhub靶场并执⾏以下命令开启靶场&#xff1b;在浏览器中访问并安装好.... 第二步&#xff1a;找到外观--编辑--404.php&#xff0c;将原内容删除并修改为一句话木马&#xff0c;点击更新--File edited successfully. &…

「清华大学、北京大学」DeepSeek 课件PPT专栏

你要的 这里都打包好啦&#xff0c;快快收藏起来&#xff01; 名称 链接 团队简介 类型 DeepSeek——从入门到精通 1️⃣ DeepSeek从入门到精通「清华团队」 清华大学新闻与传播学院 新媒体研究中心 元宇宙文化实验室 PPT课件 DeepSeek如何赋能职场应用? ——从提示语…

【docker】--- 详解 WSL2 中的 Ubuntu 和 Docker Desktop 的区别和关系!

在编程的艺术世界里,代码和灵感需要寻找到最佳的交融点,才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里,我们将共同追寻这种完美结合,为未来的世界留下属于我们的独特印记。【WSL 】--- Windows11 迁移 WSL 超详细指南 —— 给室友换一个宿舍! 开发环境一、引…

【图像处理基石】什么是HDR图片?

1. 什么是HDR图片&#xff1f; HDR&#xff08;高动态范围图像&#xff0c;High Dynamic Range&#xff09;是一种通过技术手段扩展照片明暗细节的成像方式。以下是关于HDR的详细说明&#xff1a; 核心原理 动态范围&#xff1a;指图像中最亮和最暗区域之间的亮度差。人眼能…

HarmonyOS Next中的弹出框使用

HarmonyOS Next弹出框概述及分类 弹出框是一种模态窗口&#xff0c;通常用于在保持当前上下文环境的同时&#xff0c;临时展示用户需关注的信息或待处理的操作。用户需在模态弹出框内完成相关交互任务之后&#xff0c;才能退出模态模式。弹出框可以不与任何组件绑定&#xff0…

Java多线程与高并发专题——为何每次用完 ThreadLocal 都要调用 remove()?

什么是内存泄漏 首先&#xff0c;我们要知道这个事情和内存泄漏有关&#xff0c;所以就让我们先来看一下什么是内存泄漏。 内存泄漏指的是&#xff0c;当某一个对象不再有用的时候&#xff0c;占用的内存却不能被回收&#xff0c;这就叫作内存泄漏。 因为通常情况下&#xf…

视频推拉流EasyDSS点播平台云端录像播放异常的问题排查与解决

视频推拉流EasyDSS视频直播点播平台可提供一站式的视频转码、点播、直播、视频推拉流、播放H.265视频等服务&#xff0c;搭配RTMP高清摄像头使用&#xff0c;可将无人机设备的实时流推送到平台上&#xff0c;实现无人机视频推流直播、巡检等应用。 有用户反馈&#xff0c;项目现…