HarmonyOS应用开发实战 | ArkTS中SQLite数据库初始化详解
🌟 HarmonyOS应用开发实战 | ArkTS中SQLite数据库初始化详解
💫 坚果派·红目香薰 倾情分享
🎯 用心打造每一个技术细节,为开发者创造更多价值
📱 让HarmonyOS开发变得更简单、更有趣
✨ 写在前面的话
嗨,亲爱的技术朋友们!👋
我是来自坚果派的红目香薰,一个热爱技术、专注HarmonyOS开发的程序媛。在这个数字化飞速发展的时代,HarmonyOS作为华为自主研发的操作系统,正在改变着我们的数字生活体验。
🌈 为什么要写这个系列?
- 💡 让复杂的技术变得简单易懂
- 🚀 帮助更多开发者快速上手HarmonyOS
- 💝 分享实战经验,避免踩坑
- 🌟 用代码创造美好,用技术传递温暖
每一个Demo都是我精心设计和反复测试的结果,希望能够为你的HarmonyOS开发之路点亮一盏明灯。✨
📋 Demo功能说明
🎯 核心功能
本Demo主要展示如何在HarmonyOS应用中初始化和使用SQLite数据库,实现一个简单的待办事项管理功能。通过这个Demo,你将学习到如何创建数据库、定义表结构、执行基本的CRUD操作以及处理数据库事务。
✨ 特色亮点
- 🔄 使用ArkTS的关系型存储API进行数据库操作
- 📊 实现数据的增删改查全流程
- 🛡️ 采用事务机制确保数据一致性
- 🧩 模块化设计,便于代码复用和维护
🎨 界面展示
一个简洁的待办事项列表应用,支持添加、标记完成和删除待办事项。
📱 适用场景
- 需要本地持久化存储的应用
- 待办事项、笔记、个人信息管理类应用
- 需要离线数据访问的应用场景
🔧 核心代码说明
📁 项目结构
TodoApp/
├── src/
│ ├── main/
│ │ ├── ets/
│ │ │ ├── pages/
│ │ │ │ └── Index.ets // 主页面
│ │ │ └── model/
│ │ │ └── TodoItem.ets // 数据模型
│ │ └── resources/
│ └── ...
注:所有代码均放在src/main/ets/pages/Index.ets文件中,图片放在src/main/resources/base/media目录下
🎯 关键技术点
1. SQLite数据库初始化
在本Demo中,我们将学习如何初始化SQLite数据库,创建表结构,并设置必要的配置。
2. 数据模型定义
定义待办事项的数据模型,包括ID、标题、描述、完成状态等字段。
3. 数据库操作封装
封装常用的数据库操作,如插入、查询、更新和删除,提高代码复用性。
4. 界面与数据绑定
将数据库操作与界面元素绑定,实现数据的动态展示和交互。
💡 技术要点解析
SQLite数据库初始化流程
- 导入必要的模块
- 定义数据库配置(名称、版本等)
- 创建数据库连接
- 定义表结构并创建表
- 处理数据库版本升级
📝 完整Demo代码
🏠 主页面代码
// src/main/ets/pages/Index.ets
import relationalStore from '@ohos.data.relationalStore';
import promptAction from '@ohos.promptAction';
import { BusinessError } from '@ohos.base';
// 待办事项数据接口
interface TodoItem {
id?: number;
title: string;
description: string;
isCompleted: boolean;
createTime: number;
}
// 示例数据项接口
interface SampleItem {
title: string;
description: string;
isCompleted: boolean;
}
@Entry
@Component
struct Index {
@State todoItems: TodoItem[] = [];
@State newTodoText: string = '';
private storeConfig: relationalStore.StoreConfig = {
name: 'TodoDatabase.db',
securityLevel: relationalStore.SecurityLevel.S1
};
private rdbStore: relationalStore.RdbStore | null = null;
private tableName: string = 'TodoTable';
aboutToAppear() {
// 初始化数据库
this.initDatabase();
}
async initDatabase() {
try {
// 获取上下文
const context = getContext(this);
// 获取RDB数据库实例
this.rdbStore = await relationalStore.getRdbStore(context, this.storeConfig);
// 创建表SQL语句
const createTableSql = `
CREATE TABLE IF NOT EXISTS ${this.tableName} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
description TEXT,
isCompleted INTEGER DEFAULT 0,
createTime INTEGER
)`;
// 执行创建表操作
await this.rdbStore.executeSql(createTableSql);
console.info('Database and table created successfully');
// 加载待办事项
this.loadTodoItems();
// 如果没有数据,添加一些示例数据
if (this.todoItems.length === 0) {
await this.addSampleData();
}
} catch (error) {
const err = error as BusinessError;
console.error(`Failed to initialize database: ${err.message}`);
promptAction.showToast({
message: '初始化数据库失败',
duration: 2000
});
}
}
async addSampleData() {
if (!this.rdbStore) return;
// 定义示例数据,使用SampleItem接口
const sampleItems: SampleItem[] = [
{ title: '完成项目报告', description: '周五之前提交给经理', isCompleted: false },
{ title: '购买生日礼物', description: '妈妈的生日在下周三', isCompleted: true },
{ title: '预约医生', description: '年度体检', isCompleted: false },
{ title: '学习HarmonyOS开发', description: '完成ArkTS基础课程', isCompleted: false }
];
try {
for (const item of sampleItems) {
const valuesBucket: relationalStore.ValuesBucket = {
'title': item.title,
'description': item.description,
'isCompleted': item.isCompleted ? 1 : 0,
'createTime': new Date().getTime() - Math.floor(Math.random() * 86400000) // 随机时间
};
await this.rdbStore.insert(this.tableName, valuesBucket);
}
console.info('Sample data added successfully');
this.loadTodoItems();
} catch (error) {
const err = error as BusinessError;
console.error(`Failed to add sample data: ${err.message}`);
}
}
async loadTodoItems() {
if (!this.rdbStore) return;
try {
// 定义查询条件
const predicates = new relationalStore.RdbPredicates(this.tableName);
predicates.orderByDesc('createTime');
// 执行查询
const resultSet = await this.rdbStore.query(predicates, ['id', 'title', 'description', 'isCompleted', 'createTime']);
// 清空当前列表
this.todoItems = [];
// 遍历结果集
while (resultSet.goToNextRow()) {
const id = resultSet.getLong(resultSet.getColumnIndex('id'));
const title = resultSet.getString(resultSet.getColumnIndex('title'));
const description = resultSet.getString(resultSet.getColumnIndex('description'));
const isCompleted = resultSet.getLong(resultSet.getColumnIndex('isCompleted')) === 1;
const createTime = resultSet.getLong(resultSet.getColumnIndex('createTime'));
// 添加到列表
this.todoItems.push({
id: id,
title: title,
description: description,
isCompleted: isCompleted,
createTime: createTime
});
}
// 关闭结果集
resultSet.close();
} catch (error) {
const err = error as BusinessError;
console.error(`Failed to load todo items: ${err.message}`);
promptAction.showToast({
message: '加载待办事项失败',
duration: 2000
});
}
}
async addTodoItem() {
if (!this.rdbStore) return;
if (!this.newTodoText.trim()) {
promptAction.showToast({
message: '请输入待办事项内容',
duration: 2000
});
return;
}
try {
// 创建待办事项数据
const valuesBucket: relationalStore.ValuesBucket = {
'title': this.newTodoText,
'description': '',
'isCompleted': 0,
'createTime': new Date().getTime()
};
// 插入数据
const rowId = await this.rdbStore.insert(this.tableName, valuesBucket);
console.info(`Inserted row ID: ${rowId}`);
// 清空输入框
this.newTodoText = '';
// 重新加载数据
this.loadTodoItems();
promptAction.showToast({
message: '添加成功',
duration: 2000
});
} catch (error) {
const err = error as BusinessError;
console.error(`Failed to add todo item: ${err.message}`);
promptAction.showToast({
message: '添加待办事项失败',
duration: 2000
});
}
}
async toggleTodoItem(id: number, isCompleted: boolean) {
if (!this.rdbStore) return;
try {
// 创建更新数据
const valuesBucket: relationalStore.ValuesBucket = {
'isCompleted': isCompleted ? 0 : 1
};
// 定义更新条件
const predicates = new relationalStore.RdbPredicates(this.tableName);
predicates.equalTo('id', id);
// 执行更新
const rows = await this.rdbStore.update(valuesBucket, predicates);
console.info(`Updated rows: ${rows}`);
// 重新加载数据
this.loadTodoItems();
} catch (error) {
const err = error as BusinessError;
console.error(`Failed to update todo item: ${err.message}`);
promptAction.showToast({
message: '更新待办事项失败',
duration: 2000
});
}
}
async deleteTodoItem(id: number) {
if (!this.rdbStore) return;
try {
// 定义删除条件
const predicates = new relationalStore.RdbPredicates(this.tableName);
predicates.equalTo('id', id);
// 执行删除
const rows = await this.rdbStore.delete(predicates);
console.info(`Deleted rows: ${rows}`);
// 重新加载数据
this.loadTodoItems();
promptAction.showToast({
message: '删除成功',
duration: 2000
});
} catch (error) {
const err = error as BusinessError;
console.error(`Failed to delete todo item: ${err.message}`);
promptAction.showToast({
message: '删除待办事项失败',
duration: 2000
});
}
}
build() {
Column() {
// 标题
Text('待办事项')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 20 })
// 输入框和添加按钮
Row() {
TextInput({ placeholder: '请输入待办事项...', text: this.newTodoText })
.onChange((value) => {
this.newTodoText = value;
})
.layoutWeight(1)
.height(50)
.margin({ right: 10 })
.backgroundColor('#F0F0F0')
.borderRadius(25)
.padding({ left: 20, right: 20 })
Button('添加')
.onClick(() => {
this.addTodoItem();
})
.height(50)
.width(80)
.borderRadius(25)
.backgroundColor('#0A59F7')
}
.width('90%')
.margin({ bottom: 20 })
// 待办事项列表
List({ space: 8, initialIndex: 0 }) {
ForEach(this.todoItems, (item: TodoItem) => {
ListItem() {
Column() {
Row() {
Checkbox()
.select(item.isCompleted)
.onChange(() => {
this.toggleTodoItem(item.id!, item.isCompleted);
})
.margin({ right: 10 })
Text(item.title)
.fontSize(16)
.decoration({ type: item.isCompleted ? TextDecorationType.LineThrough : TextDecorationType.None })
.fontColor(item.isCompleted ? '#999999' : '#333333')
.layoutWeight(1)
Button({ type: ButtonType.Circle, stateEffect: true }) {
Row() {
Text('删')
.fontSize(14)
.fontWeight(FontWeight.Normal)
.fontColor('#FFFFFF')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
.width(36)
.height(36)
.backgroundColor('#FF4757')
.onClick(() => {
this.deleteTodoItem(item.id!);
})
}
.width('100%')
.alignItems(VerticalAlign.Center)
if (item.description) {
Text(item.description)
.fontSize(14)
.fontColor('#666666')
.margin({ top: 5, left: 34 })
.opacity(item.isCompleted ? 0.6 : 1.0)
}
}
.width('100%')
.padding(15)
.borderRadius(12)
.backgroundColor(Color.White)
.shadow({
radius: 6,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
})
}
.width('90%')
.layoutWeight(1)
// 底部状态栏
Row() {
Text(`共 ${this.todoItems.length} 项`)
.fontSize(14)
.fontColor('#666666')
Text(`已完成 ${this.todoItems.filter(item => item.isCompleted).length} 项`)
.fontSize(14)
.fontColor('#27AE60')
}
.width('90%')
.justifyContent(FlexAlign.SpaceBetween)
.padding({ top: 10, bottom: 10 })
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
.padding({ top: 10, bottom: 10 })
}
}
🚀 运行效果
📱 界面展示
运行后,你将看到一个简洁的待办事项应用界面:
- 顶部是应用标题"待办事项"
- 中间是输入框和添加按钮,用于创建新的待办事项
- 下方是待办事项列表,每个项目包含复选框和删除按钮
- 点击复选框可以标记待办事项为已完成/未完成
- 点击删除按钮可以移除待办事项
✅ 功能验证
- 添加待办事项:在输入框中输入内容,点击"添加"按钮
- 标记完成:点击待办事项前的复选框
- 删除待办事项:点击待办事项右侧的删除按钮
- 数据持久化:关闭应用后重新打开,数据仍然存在
💡 开发小贴士
🎯 最佳实践
- 💫 数据库操作异步化:所有数据库操作都应该是异步的,避免阻塞主线程
- 🎨 错误处理:对所有数据库操作进行适当的错误处理,提高应用稳定性
- ⚡ 事务使用:对于多步操作,使用事务确保数据一致性
- 🔧 关闭资源:及时关闭ResultSet等资源,避免内存泄漏
🚨 常见问题
-
数据库初始化失败:检查权限设置和存储空间
// 在module.json5中添加数据权限 "requestPermissions": [ { "name": "ohos.permission.DISTRIBUTED_DATASYNC" } ]
-
查询结果为空:检查表名和字段名是否正确,SQL语句是否有语法错误
// 使用日志输出SQL语句进行调试 console.info(`Executing SQL: ${sql}`);
-
版本升级问题:处理数据库版本升级时的表结构变更
// 在StoreConfig中指定版本号 const storeConfig = { name: 'TodoDatabase.db', securityLevel: relationalStore.SecurityLevel.S1, version: 2 // 指定版本号 };
🎉 总结与展望
通过这个Demo,我们学习了:
- ✨ 如何在ArkTS中初始化SQLite数据库
- 🎯 如何执行基本的CRUD操作
- 💡 如何将数据库操作与UI交互结合
SQLite数据库为HarmonyOS应用提供了强大的本地数据存储能力,适合各种需要持久化存储的应用场景。在实际开发中,我们可以进一步优化数据库结构,添加更多功能,如数据同步、搜索、分类等,打造更加完善的应用。
🔗 相关资源
🌟 如果这篇文章对你有帮助,请点赞支持!🌟
让我们一起在HarmonyOS的世界里创造更多可能!
© 2024 坚果派·红目香薰 | 用心分享,用技术创造价值
更多推荐
所有评论(0)