【鸿蒙HarmonyOS NEXT】数据存储之用户首选项Preference
一、环境说明
-
DevEco Studio 版本:
-
API版本:
以12为主
二、Preference运作机制
应用场景:
用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。当用户希望有一个全局唯一存储的地方,可以采用用户首选项来进行存储。Preferences会将该数据缓存在内存中,当用户读取的时候,能够快速从内存中获取数据,当需要持久化时可以使用flush接口将内存中的数据写入持久化文件中。Preferences会随着存放的数据量越多而导致应用占用的内存越大,因此,Preferences不适合存放过多的数据,也不支持通过配置加密,适用的场景一般为应用保存用户的个性化设置(字体大小,是否开启夜间模式)等。
Preference运作机制:
用户程序通过ArkTS接口调用用户首选项读写对应的数据文件。开发者可以将用户首选项持久化文件的内容加载到Preferences实例,每个文件唯一对应到一个Preferences实例,系统会通过静态容器将该实例存储在内存中,直到主动从内存中移除该实例或者删除该文件。应用首选项的持久化文件保存在应用沙箱内部,可以通过context获取其路径。
三、示例代码加以说明
沿用【鸿蒙HarmonyOS NEXT】页面之间相互传递参数博文中的代码,进行测试。
代码改写如下:
-
LoginPage完整代码如下:
typescriptimport { router } from '@kit.ArkUI'; // 引入Context相关 import { common } from '@kit.AbilityKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; // 引入preferences相关 import { preferences } from '@kit.ArkData'; import { util } from '@kit.ArkTS'; // 定义ihlog日志常量相关 const TAG: string = '[LoginPage_Context]'; const DOMAIN_NUMBER: number = 0xFF00; @Preview @Entry @Component struct LoginPage { @State message: string = '登录页'; @State btnMsg: string = '登录'; @State account: string = ''; // 账号状态变量 @State password: string = ''; // 密码状态变量 @State isShowProgress: boolean = false; // 显示进度指示器的状态变量 // 获取Context private context = getContext(this) as common.UIAbilityContext; // 获取首选项对象,其中userInfo可自定义 private options: preferences.Options = { name: 'userInfo' }; private dataPreferences: preferences.Preferences = preferences.getPreferencesSync(this.context, this.options); build() { Column() { Text(this.message) .id('HelloWorld') .fontSize(20) .fontWeight(FontWeight.Bold) .width('100%') .height(50) .textAlign(TextAlign.Center) .backgroundColor(0xF1F3F5) Image($r('app.media.startIcon')) .width(150) .height(150) .margin({ top: 40, bottom: 40 }) TextInput({ placeholder: '请输入手机号' }) .maxLength(11)// 最大长度 .type(InputType.Number)// 输入类型为数字 .inputStyle()// 应用自定义样式 .onChange((value: string) => { this.account = value; // 更新账号状态 }) Line().lineStyle() // 应用自定义Line样式 // 密码输入框 TextInput({ placeholder: '请输入密码' }) .maxLength(12)// 最大长度 .type(InputType.Password)// 输入类型为密码 .inputStyle()// 应用自定义样式 .onChange((value: string) => { // TODO: 生产环境需要使用正则表达式对手机号进行验证 this.password = value; // 更新密码状态 }) Line().lineStyle() // 应用自定义Line样式 Button(this.btnMsg) .width('80%') .margin({ top: 100 }) .height(50) .onClick(() => { if (this.account === undefined || this.account === '') { console.info('请输入账号') return } if (this.password === undefined || this.password === '') { console.info('请输入密码') return } // 使用ArkData用户首选项 本地以Key/Value形式存储用户信息数据 if (this.dataPreferences.hasSync('account')) { hilog.info(DOMAIN_NUMBER, TAG, `account: ${this.account}`); } else { hilog.info(DOMAIN_NUMBER, TAG, `The key 'account' does not contain.`); // 此处以此键值对不存在时写入数据为例 this.dataPreferences.putSync('account', this.account); // 当字符串有特殊字符时,需要将字符串转为Uint8Array类型再存储 let uInt8Password = new util.TextEncoder().encodeInto(this.password); this.dataPreferences.putSync('password', uInt8Password); } // 跳转到首页 router.pushUrl({ url: 'pages/HomePage', params: { account: this.account, password: this.password } }) }) } .height('100%') .width('100%') .padding(0) } } // TextInput组件的自定义样式扩展 @Extend(TextInput) function inputStyle() { .placeholderColor(Color.Gray) // 占位符颜色 .height(50) // 输入框高度 .fontSize(15) // 字体大小 .backgroundColor(0xF1F3F5) // 背景颜色 .width('90%') // 宽度为父组件的100% .padding({ left: 12 }) // 左侧填充 .margin({ top: 15 }) // 上方边距 } // Line组件的自定义样式扩展 @Extend(Line) function lineStyle() { .width('100%') // 宽度为父组件的100% .height(1) // 高度 .backgroundColor(0xF1F3F5) // 背景颜色 }
-
HomePage完整代码如下:
typescriptimport { router } from '@kit.ArkUI'; import { preferences } from '@kit.ArkData'; import {common} from '@kit.AbilityKit' import { util } from '@kit.ArkTS'; import { hilog } from '@kit.PerformanceAnalysisKit'; // 定义ihlog日志常量相关 const TAG: string = '[HomePage_Context]'; const DOMAIN_NUMBER: number = 0xFF01; @Preview @Entry @Component struct HomePage { @State message: string = '首页'; // 获取前一个页面传递过来的数据 @State account: string = '' @State password: string = '' // 获取Context private context = getContext(this) as common.UIAbilityContext; // 获取首选项对象 private options: preferences.Options = { name: 'userInfo' }; private dataPreferences: preferences.Preferences = preferences.getPreferencesSync(this.context, this.options); aboutToAppear(): void { // 使用ArkData用户首选项 获取用户数据 this.account = this.dataPreferences.getSync('account', 'default').toString(); // 'default' 可以换成其他的,如null,但这个参数必须给 hilog.info(DOMAIN_NUMBER, TAG, `account: ${this.account}`); // 当获取的值为带有特殊字符的字符串时,需要将获取到的Uint8Array转换为字符串 let uInt8Array2 : preferences.ValueType = this.dataPreferences.getSync('password', new Uint8Array(0)); let textDecoder = util.TextDecoder.create('utf-8'); this.password = textDecoder.decodeToString(uInt8Array2 as Uint8Array); hilog.info(DOMAIN_NUMBER, TAG, `password: ${this.password}`); } build() { Column() { Text(this.message) .fontSize(30) .width('100%') .height(50) .textAlign(TextAlign.Center) .backgroundColor(0xF1F3F5) Blank().height(120) Text(`接收到的用户名:${this.account}`) .fontSize(20) .width('100%') .height(50) .padding({ left: 12, right: 12 }) Text(`接收到的密码:${this.password}`) .fontSize(20) .width('100%') .height(50) .padding({ left: 12, right: 12 }) Button('返回上一页') .width('80%') .margin({ top: 120 }) .height(50) .onClick(() => { // 返回登录页面 router.showAlertBeforeBackPage({ message: '确认返回上一页吗?' }) router.back({ url: 'pages/LoginPage', params: { msg: 'homepage' } }) }) } .height('100%') .width('100%') } }
测试步骤如下:
- 打开模拟器,并将代码部署到模拟器上,当模拟器正常运行代码后,
输入用户名和密码
:
- 点击手机模拟器上应用的登录按钮,
跳转到了首页
,然后再从首页返回登录页,查看控制台日志,内容如截图红色框或者首页文字所示:
四、小结
通过上述的说明和示例演示,相信大家已经很清楚Preferences用户首选项存储数据的用法了。细心的读者朋友可能会问,如何调用flush持久化到文件中以及如何删除文件?另外,在真实的开发过程中Preferences不适合存放过多的数据,也不支持通过配置加密,适用的场景一般为应用保存用户的个性化设置(字体大小,是否开启夜间模式)等。HarmonyOS官网推荐使用键值型数据库持久化此类数据。感兴趣的读者朋友可以尝试下,看看使用键值型数据库持久化此类数据是否可以正常运行呢?欢迎大家的留言,我们在留言区进行讨论。