【HarmonyOS系列课程体验测评4】保存应用数据
鸿蒙应用数据持久化课程解析:从用户首选项到关系型数据库 这门课程系统讲解了鸿蒙应用开发中的数据持久化技术,包含两个核心模块: 用户首选项:用于存储轻量键值对数据,如主题偏好、浏览记录等,通过flush()确保数据持久化; 关系型数据库:基于SQLite封装,适合管理结构化业务数据,课程详细演示了增删查改操作和事务处理。 课程特色: 梯度式教学,从基础到实战 强调技术选型逻辑 包含防呆设计细节 提供
作为一个每天和鸿蒙应用打交道的开发者,我深知 “数据持久化” 有多重要 —— 总不能每次打开 APP,用户都得重新设置偏好、重新加载所有数据吧?
上节给大家介绍了从网络获取数据的课程,接下来跟大家聊聊这门课的核心内容、实用价值,还有我自己的学习感受。
课程链接:<HarmonyOS第一课>保存应用数据
一、课程核心内容拆解
这门课把 “保存应用数据” 拆成了几个梯度分明的模块,从最基础的 “用户习惯记忆”,到 “结构化数据管理”,再到 “实战落地”,每一块都能解决实际开发里的 “数据留存” 痛点。
1. 用户首选项的使用
“用户首选项” 是鸿蒙里存轻量键值对数据的工具,像用户的 “深色 / 浅色主题偏好”“默认字体大小”,甚至 “上次浏览到哪篇文章”,都能靠它实现 “记忆”。
用户首选项运作机制:
课程从 “基础使用” 开始,一步步带练:先通过Preferences.getPreferences(context, name)获取首选项实例,相当于 “打开记忆小本本”;接着用put方法存数据(支持布尔、字符串、数字等类型),比如把 “用户是否开启通知” 存为布尔值;再用get方法取数据,还能设置默认值(比如用户没设置过主题,就默认给个浅色主题),防止程序因为 “数据不存在” 崩溃。
“实现数据持久化” 这部分,还重点讲了 “数据提交”—— 因为首选项是异步缓存的,必须调用flush()方法,才能确保数据真正存到本地文件里。
dataPreferences.flush((err: BusinessError) => {
if (err) {
console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
return;
}
console.info('Succeeded in flushing.');
})
这步看似微小,却能避免 “用户刚设置完,APP 突然崩溃导致配置丢失” 的尴尬,课程把这种 “防呆细节” 讲透了,对新手特别友好。
2. 关系型数据库的使用
如果应用要存复杂且关联的数据(比如记账 APP 的 “账单表”“分类表”,社交 APP 的 “用户表”“好友关系表”),关系型数据库就是核心工具。鸿蒙的关系型数据库基于 SQLite 封装,课程从 “创建数据库与表结构” 教起:用RelationalStore创建数据库,通过DataAbilityHelper执行 SQL 语句建表。接着详细讲解 “增删查改” 四大操作:
2.1 新增数据
把用户信息封装成ValuesBucket对象,插入到表中;
let value1 = 'Lisa';
let value2 = 18;
let value3 = 100.5;
let value4 = new Uint8Array([1, 2, 3, 4, 5]);
let value5 = BigInt('15822401018187971961171');
const valueBucket: relationalStore.ValuesBucket = {
NAME: value1,
AGE: value2,
SALARY: value3,
CODES: value4,
IDENTITY: value5,
};
if (store !== undefined) {
try {
const rowId = await store.insert('EMPLOYEE', valueBucket);
console.info(`Succeeded in inserting data. rowId:${rowId}`);
} catch (error) {
const err = error as BusinessError;
console.error(`Failed to insert data. Code:${err.code}, message:${err.message}`);
}
}
2.2 查询数据
调用query()方法查找数据,返回一个ResultSet结果集。;
let predicates2 = new relationalStore.RdbPredicates('EMPLOYEE');
predicates2.equalTo('NAME', 'Rose');
if (store !== undefined) {
(store as relationalStore.RdbStore).query(predicates2, ['ID', 'NAME', 'AGE', 'SALARY', 'IDENTITY'], (err: BusinessError, resultSet) => {
if (err) {
console.error(`Failed to query data. Code:${err.code}, message:${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'));
const identity = resultSet.getValue(resultSet.getColumnIndex('IDENTITY'));
console.info(`id=${id}, name=${name}, age=${age}, salary=${salary}, identity=${identity}`);
}
// 释放数据集的内存
resultSet.close();
})
}
2.3 修改 / 删除数据
通过 SQL 或封装方法,更新特定条件的数据,或删除冗余记录。
if (store !== undefined) {
// 创建事务对象
try {
const transaction = await store.createTransaction();
try {
// 使用事务对象插入数据
const rowId = await transaction.insert(
'EMPLOYEE',
{
NAME: 'Lisa',
AGE: 18,
SALARY: 100.5,
CODES: new Uint8Array([1, 2, 3, 4, 5])
},
relationalStore.ConflictResolution.ON_CONFLICT_REPLACE
);
console.info(`Insert is successful, rowId = ${rowId}`);
const predicates = new relationalStore.RdbPredicates('EMPLOYEE');
predicates.equalTo('NAME', 'Lisa');
// 使用事务对象更新数据
const rows = await transaction.update(
{
NAME: 'Rose',
AGE: 22,
SALARY: 200.5,
CODES: new Uint8Array([1, 2, 3, 4, 5])
},
predicates,
relationalStore.ConflictResolution.ON_CONFLICT_REPLACE
);
console.info(`Updated row count: ${rows}`);
// 使用事务对象删除数据
await transaction.execute('DELETE FROM EMPLOYEE WHERE age = ? OR age = ?', [21, 20]);
console.info(`execute delete success`);
// 提交事务
await transaction.commit();
console.info('Transaction commit success.');
} catch (error) {
const err = error as BusinessError;
// 执行失败回滚事务
await transaction.rollback();
console.error(`Transaction execute failed, code is ${err.code}, message is ${err.message}`);
}
} catch (error) {
const err = error as BusinessError;
console.error(`createTransaction failed, code is ${err.code}, message is ${err.message}`);
}
}
课程还特意对比了 “用户首选项” 和 “关系型数据库” 的适用场景:首选项适合存零散的 “配置项”,数据库适合存 “成体系的业务数据”。这让我瞬间清晰了技术选型逻辑 —— 就像家里的小物件(钥匙、耳机)可以放桌面收纳盒(首选项),但大量书籍、文件就得放书柜(数据库)。
我跟着做了个 “简易记账本” 案例,建了 “账单表” 存消费金额、类型、日期,然后用查询功能统计 “本月餐饮支出”。看着 SQL 语句执行后,精准算出我(模拟的)花在咖啡上的钱,突然觉得 “数据库不再是天书,而是能帮我管理数据的助手”。
二、这门课的 “实用价值”
这门课解决的是鸿蒙应用的 “留存感” 问题 —— 用户用你的 APP,不光是当下能操作,下次打开还能接着用,甚至能记住用户习惯。“用户首选项” 让应用有 “小记性”,记住用户偏好;“关系型数据库” 让应用有 “大内存”,管理复杂业务数据;案例则教会我们 “怎么把这些数据变成用户能看到、能交互的界面”。对开发者来说,这是打造 “长期可用、体验连贯” 应用的必经之路。
三、学习感受
聊到主观感受,可得好好说说。以前我做应用,最担心 “用户数据存不住”—— 比如用户辛苦设置的主题,一重启 APP 就没了,特别影响体验。学这门课的时候,我正一边啃着便利店的饭团(赶工赶得没时间正经吃饭),一边跟着做 “用户首选项保存主题” 的 Demo。
第一次做的时候,忘了调用flush(),结果 APP 重启后,主题又回到默认了。当时有点懊恼,但仔细看课程里的 “注意事项”,才发现这个关键步骤。改完再试,APP 真的 “记住” 了我选的深色主题,那一刻的成就感,比饭团里吃到脆骨还开心。
在之前学习 “关系型数据库” 时,因为涉及 SQL 语句,我一开始有点发怵(之前对数据库操作不算熟练)。但课程把 “建表→插入→查询” 拆得特别细,还配了很多 “错误示例→正确解法” 的对比,比如 “忘记给字段加类型导致插入失败”“查询条件写错导致查不到数据”,跟着改几遍,就慢慢找到感觉了。现在我甚至能自己写简单的联表查询,那种 “掌控数据” 的感觉,让我对开发复杂应用更有底气了。
学完这门课会发现这门课程不是在教 “死技术”,而是在教 “怎么让应用更懂用户”。掌握了 “保存应用数据” 的能力,应用就不再是 “一次性工具”,而是能和用户 “长期互动” 的伙伴。就像现在,我喝完手边的美式,又能带着期待继续探索剩下的内容啦~
如果你也和我一样,在学习中经历过 “认知破碎 — 重建 — 兴奋” 的循环,或是对鸿蒙开发有无数疑问
欢迎加入 鸿蒙知识共建交流群 :点击直达
在这里,我们可以拆解技术难点,分享实践案例,甚至一起畅想全场景生态的下一个突破点 —— 毕竟,在鸿蒙的浪潮里,独行太孤独,并肩才能走得更远。
更多推荐


所有评论(0)