第八章:数据持久化
本章配套代码:
code/Chapter8(Preferences 键值存储 Demo) 前置要求:已完成状态管理与列表章节 参考:鸿蒙学苑-数据持久化案例
8.1 学习目标
- 理解 HarmonyOS 三种数据持久化方案及选型
- 掌握 Preferences 用户首选项的增删改查
- 了解 KVStore 键值数据库
- 了解关系型数据库(RDB)
- 学会封装工具类提高复用性
8.2 存储方案选型
| 方案 | 适用场景 | 特点 | 依赖 |
|---|---|---|---|
| Preferences | 用户设置、配置项 | 轻量、键值对、简单 | @kit.ArkData |
| KVStore | 缓存、分布式数据 | 键值对、支持分布式 | @kit.ArkData |
| 关系型数据库 | 复杂关系数据 | SQL、表结构、事务 | @kit.ArkData |
选择决策树:
┌─ 只是少量配置/设置?─────> Preferences ✅
├─ 键值缓存/需多设备同步?─> KVStore ✅
├─ 结构化、需查询关联?───> 关系型数据库 ✅
└─ 需云上同步?──────────> 端云(第十三章)✅
8.3 Preferences 用户首选项
8.3.1 核心概念
Preferences 以 key-value 形式存储轻量数据,适合应用配置。
Preferences 实例(文件: my_store)
├── "fontSize": 16
├── "darkMode": true
└── "username": "张三"
核心 API:
| API | 说明 |
|---|---|
preferences.getPreferences(context, name) | 获取实例(异步) |
getPreferencesSync(context, { name }) | 获取实例(同步) |
put(key, value) | 写入 |
flush() | 刷盘(持久化) |
get(key, defValue) | 读取 |
delete(key) | 删除 |
getAllSync() | 获取全部 |
8.3.2 基本使用
import { preferences } from '@kit.ArkData'
async function demo(context: Context) {
// ① 获取 Preferences 实例
const pref = await preferences.getPreferences(context, 'my_store')
// ② 写入
await pref.put('fontSize', 16)
await pref.put('darkMode', true)
await pref.flush() // 重要:写入后必须 flush 才持久化
// ③ 读取
const fontSize = await pref.get('fontSize', 16)
const darkMode = await pref.get('darkMode', false)
// ④ 删除
await pref.delete('fontSize')
await pref.flush()
}
⚠️
put后必须调用flush(),否则数据只存内存,重启丢失!
8.3.3 封装工具类
为保证整洁与复用,封装 PreferencesUtil:
import { preferences } from '@kit.ArkData'
class PreferencesUtil {
private prefs: Map<string, preferences.Preferences> = new Map()
init(context: Context, name: string) {
const pref = preferences.getPreferencesSync(context, { name })
this.prefs.set(name, pref)
}
put(prefName: string, key: string, value: preferences.ValueType) {
const pref = this.prefs.get(prefName)
pref?.putSync(key, value)
pref?.flush()
}
get(prefName: string, key: string, def: preferences.ValueType): preferences.ValueType {
return this.prefs.get(prefName)?.getSync(key, def) ?? def
}
}
export default new PreferencesUtil()
💡 用
Map管理多个 Preferences 实例,避免重复创建;同步 API 简化调用。
8.4 综合示例:Preferences 增删改查
对应 code/Chapter8 的 Index.ets,完整可运行的键值存储页面:
import { preferences } from '@kit.ArkData'
@Entry
@ComponentV2
struct Index {
@Local savedKey: string = ''
@Local savedValue: string = ''
@Local storedData: Map<string, string> = new Map()
@Local statusMessage: string = ''
private pref?: preferences.Preferences
async aboutToAppear(): Promise<void> {
await this.initPreferences()
}
async initPreferences(): Promise<void> {
const context = this.getUIContext().getHostContext()
this.pref = await preferences.getPreferences(context, 'my_store')
this.loadAll()
}
loadAll(): void {
const all = this.pref?.getAllSync()
const map: Map<string, string> = new Map()
if (all) {
all.forEach((value: preferences.ValueType, key: string) => {
map.set(key, String(value))
})
}
this.storedData = map
}
async saveData(): Promise<void> {
if (!this.savedKey || !this.savedValue) {
this.statusMessage = '请输入 Key 和 Value'
return
}
await this.pref?.put(this.savedKey, this.savedValue)
await this.pref?.flush()
this.savedKey = ''
this.savedValue = ''
this.statusMessage = '保存成功'
this.loadAll()
}
async deleteData(key: string): Promise<void> {
await this.pref?.delete(key)
await this.pref?.flush()
this.statusMessage = `已删除: ${key}`
this.loadAll()
}
async clearAll(): Promise<void> {
await this.pref?.clear()
await this.pref?.flush()
this.statusMessage = '已清空'
this.loadAll()
}
build() {
Column({ space: 16 }) {
Text('Chapter 8: 数据持久化')
.fontSize(24)
.fontWeight(FontWeight.Bold)
Text('Preferences 用户首选项')
.fontSize(14)
.fontColor('#666666')
// 输入区
Column({ space: 8 }) {
TextInput({ placeholder: 'Key', text: this.savedKey })
.width('100%')
.height(44)
.onChange((v: string) => { this.savedKey = v })
TextInput({ placeholder: 'Value', text: this.savedValue })
.width('100%')
.height(44)
.onChange((v: string) => { this.savedValue = v })
}
.width('100%')
Row({ space: 12 }) {
Button('保存')
.layoutWeight(1)
.height(44)
.onClick(() => this.saveData())
Button('清空')
.layoutWeight(1)
.height(44)
.type(ButtonType.Normal)
.onClick(() => this.clearAll())
}
.width('100%')
Text(this.statusMessage)
.fontSize(14)
.fontColor('#007DFF')
Divider()
// 数据列表
Text(`已存储数据 (${this.storedData.size} 条)`)
.fontSize(16)
.fontWeight(FontWeight.Bold)
if (this.storedData.size === 0) {
Text('暂无数据,请添加')
.fontSize(14)
.fontColor('#999999')
} else {
List({ space: 8 }) {
ForEach(Array.from(this.storedData.keys()), (key: string) => {
ListItem() {
Row() {
Text(key)
.fontSize(14)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Text(this.storedData.get(key) ?? '')
.fontSize(14)
.fontColor('#666666')
.layoutWeight(2)
Button('删除')
.fontSize(12)
.height(30)
.type(ButtonType.Normal)
.onClick(() => this.deleteData(key))
}
.width('100%')
.padding(12)
.backgroundColor(Color.White)
.borderRadius(8)
}
})
}
.layoutWeight(1)
}
}
.width('100%')
.height('100%')
.padding(16)
.backgroundColor('#f5f5f5')
}
}
运行效果:
- 输入 Key 和 Value,点击"保存"写入 Preferences 并刷盘
- 已存储数据以列表展示(键 + 值 + 删除按钮)
- 删除后列表与磁盘同步更新
- 杀掉应用重启后数据仍存在(持久化验证)
运行效果截图:





💡 测试持久化:保存几条数据 → 停止应用 → 重新启动 → 数据自动加载,即验证持久化成功。
8.5 KVStore 键值数据库
适合缓存与分布式场景,支持同步:
import { distributedKVStore } from '@kit.ArkData'
async function initKvStore(context: Context) {
const kvManagerConfig: distributedKVStore.KVManagerConfig = {
context,
bundleName: context.applicationInfo.name as string
}
const kvManager = distributedKVStore.createKVManager(kvManagerConfig)
const options: distributedKVStore.Options = {
createIfMissing: true,
encrypt: false,
backup: false,
autoSync: false,
kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
securityLevel: distributedKVStore.SecurityLevel.S1
}
const kvStore = await kvManager.getKVStore<distributedKVStore.SingleKVStore>(
'my_kv_store', options
)
// 写入/读取/删除
await kvStore.put('username', '张三')
const name = await kvStore.get('username')
await kvStore.delete('username')
}
💡 KVStore 的
put值类型限制为Uint8Array | string | number | boolean,不支持对象,需JSON.stringify。
| KVStore 类型 | 说明 |
|---|---|
SINGLE_VERSION | 单版本(本地为主) |
DEVICE_COLLABORATION | 多设备协同(分布式) |
8.6 关系型数据库(RDB)
适合结构化数据,支持 SQL 查询:
import { relationalStore } from '@kit.ArkData'
async function initRdb(context: Context) {
const config: relationalStore.StoreConfig = {
name: 'app.db',
securityLevel: relationalStore.SecurityLevel.S1
}
const rdbStore = await relationalStore.getRdbStore(context, config)
// 建表
await rdbStore.executeSql(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER
)
`)
// 插入
await rdbStore.insert('users', { name: '张三', age: 25 })
// 查询
const predicates = new relationalStore.RdbPredicates('users')
const resultSet = await rdbStore.query(predicates)
while (resultSet.goToNextRow()) {
const name = resultSet.getString(resultSet.getColumnIndex('name'))
console.log(name)
}
resultSet.close()
// 删除
const delPredicates = new relationalStore.RdbPredicates('users')
delPredicates.equalTo('id', 1)
await rdbStore.delete(delPredicates)
}
| 操作 | API |
|---|---|
| 建表/DDL | executeSql |
| 插入 | insert(table, values) |
| 查询 | query(predicates) |
| 更新 | update(values, predicates) |
| 删除 | delete(predicates) |
| 谓词 | RdbPredicates.equalTo/greaterThan/... |
⚠️
ResultSet使用后必须close(),否则泄漏资源。
8.7 数据安全
| 措施 | 说明 |
|---|---|
| 安全级别 | SecurityLevel.S1/S2/S3/S4 控制访问 |
| 加密存储 | KVStore encrypt: true |
| 敏感数据 | 不落盘或加密后存储 |
| 备份 | 通过 backup 能力导出 |
8.8 常见问题
Q:Preferences 写入后重启丢失?
检查是否调用了 flush()。put 只写内存,flush() 才持久化。
Q:KVStore 能存对象吗?
不能直接存对象。用 JSON.stringify(obj) 转字符串存储,读取时 JSON.parse。
Q:如何选择 Preferences 还是 KVStore? 简单配置用 Preferences;需要多设备 同步或大数据量缓存用 KVStore。
Q:getPreferencesSync 和 getPreferences 区别?
同步版可直接赋值,异步版用 await。页面初始化建议用异步版避免阻塞。
8.9 本章小结
| 知识点 | 说明 |
|---|---|
| Preferences | 轻量键值对,put+flush+get |
| KVStore | 键值数据库,支持分布式 |
| RDB | 关系型数据库,SQL 查询 |
| 工具类封装 | 提高复用与可维护性 |
| 数据安全 | 安全级别与加密 |
8.10 课后练习
- 实现用户设置页:字号(Slider)、深色模式(Toggle)用 Preferences 持久化
- 封装
KvStoreUtil工具类并实现用户信息存取 - 用 RDB 实现联系人管理(增删改查)
- 将练习整合进
Chapter8/Index.ets