鸿蒙应用开发(HarmonyOS)通过TaskPool线程中操作关系型数据库实现场景
本示例通过通讯录场景实例进行讲解,介绍了在 TaskPool 线程中操作关系型数据库的方法,涵盖了单条插入(新增联系人)、批量插入(通讯录同步)、删除(删除联系人)、修改(更新联系人信息)和查询等基本操作。
·
鸿蒙NEXT开发实战往期必看文章:
一分钟了解”纯血版!鸿蒙HarmonyOS Next应用开发!
“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)
HarmonyOS NEXT应用开发案例实践总结合(持续更新......)
HarmonyOS NEXT应用开发性能优化实践总结(持续更新......)
介绍
本示例通过通讯录场景实例进行讲解,介绍了在 TaskPool 线程中操作关系型数据库的方法,涵盖了单条插入(新增联系人)、批量插入(通讯录同步)、删除(删除联系人)、修改(更新联系人信息)和查询等基本操作。
效果图预览

使用说明
-
首次进入页面,出现“点击同步通讯录数据”按钮。点击按钮后,将本地 JSON 数据分批插入数据库中。
-
同步完成后,页面显示通讯录列表。点击列表项进入联系人的详情页面,点击加号按钮进入新增联系人页面。
-
在详情页面,可以对联系人信息进行修改和删除操作。
实现思路
- 首先,构建一个关系型数据库并封装数据库操作方法涉及几个关键步骤。
- 通过getRdbStore方法初始化一个关系型数据库,用户可以根据STORE_CONFIG配置RdbStore的参数,使用Promise异步回调。
// 初始化数据库 public async initRdbStore(context: common.Context): Promise<void> { this.rdbStore = await rdb.getRdbStore(context, STORE_CONFIG); await this.createTable(); } - 使用executeSql接口初始化数据库表结构和相关数据。
// 创建数据库表 private async createTable(): Promise<void> { await this.rdbStore.executeSql(SQL_CREATE_TABLE); } - 封装数据库操作方法分别为数据插入、数据删除、数据查询和数据查询。
// 单条数据插入数据库 public async insertData(context: common.Context, Contact: Contact): Promise<void> { let value1 = Contact.name; let value2 = Contact.phone; let value3 = Contact.email; let value4 = Contact.address; let value5 = Contact.avatar; let value6 = Contact.category; const valueBucket: ValuesBucket = { 'name': value1, 'phone': value2, 'email': value3, 'address': value4, 'avatar': value5, 'category': value6 } if (this.rdbStore != undefined) { let ret = await this.rdbStore.insert(TABLE_NAME, valueBucket, rdb.ConflictResolution.ON_CONFLICT_REPLACE); } } // 批量插入数据库 public async batchInsertData(context: common.Context, array: Array<Contact>): Promise<void> { let valueBuckets: Array<ValuesBucket> = []; for (let index = 0; index < array.length; index++) { let contactItem = array[index] as Contact; let value1 = contactItem.name; let value2 = contactItem.phone; let value3 = contactItem.email; let value4 = contactItem.address; let value5 = contactItem.avatar; let value6 = contactItem.category; const valueBucket: ValuesBucket = { 'name': value1, 'phone': value2, 'email': value3, 'address': value4, 'avatar': value5, 'category': value6 } valueBuckets.push(valueBucket); } if (this.rdbStore != undefined) { let ret = await this.rdbStore.batchInsert(TABLE_NAME, valueBuckets); } } // 删除操作 public async deleteData(context: common.Context, Contact: Contact): Promise<void> { this.rdbStore = await rdb.getRdbStore(context, STORE_CONFIG); predicates.or().equalTo('id', Contact.id); this.rdbStore.delete(predicates, (err: BusinessError, row: number) => { if (err) { logger.info(TAG, "delete failed, err: " + err); return; } logger.info(TAG, `delete contact success:${row}`); promptAction.showToast({ message: $r('app.string.operate_rdb_in_taskpool_delete_prompt_text', Contact.name), duration: CommonConstants.PROMPT_DURATION_TIME }); }); } // 更新数据库 public async updateData(context: common.Context, Contact: Contact): Promise<void> { logger.info(TAG, 'update begin'); if (!context) { logger.info(TAG, 'context is null or undefined'); } const predicates = new rdb.RdbPredicates(TABLE_NAME); if (predicates === null || predicates === undefined) { logger.info(TAG, 'predicates is null or undefined'); } if (!this.rdbStore) { logger.info(TAG, 'update rdbStore is null'); await this.initRdbStore(context); } let value1 = Contact.name; let value2 = Contact.phone; let value3 = Contact.email; let value4 = Contact.address; let value5 = Contact.avatar; let value6 = Contact.category; const valueBucket: ValuesBucket = { 'name': value1, 'phone': value2, 'email': value3, 'address': value4, 'avatar': value5, 'category': value6 } predicates.equalTo("id", Contact.id); if (this.rdbStore != undefined) { this.rdbStore.update(valueBucket, predicates, rdb.ConflictResolution.ON_CONFLICT_REPLACE, (err: BusinessError, row: number) => { if (err) { logger.info(TAG, "updated failed, err: " + err) return } logger.info(TAG, `update done:${row}`); promptAction.showToast({ message: $r('app.string.operate_rdb_in_taskpool_update_prompt_text', Contact.name), duration: CommonConstants.PROMPT_DURATION_TIME }); }) } } // 查询数据库 public async query(context: common.Context): Promise<Array<Contact>> { if (!context) { logger.info(TAG, 'context is null or undefined'); return []; } let predicates = new rdb.RdbPredicates(TABLE_NAME); predicates.orderByAsc("category") if (predicates === null || predicates === undefined) { logger.info(TAG, 'predicates is null or undefined'); return []; } try { this.rdbStore = await rdb.getRdbStore(context, STORE_CONFIG); const resultSet: rdb.ResultSet = await this.rdbStore.query(predicates); logger.info(TAG, 'result is ' + JSON.stringify(resultSet.rowCount)); // 处理查询到的结果数组 return this.getListFromResultSet(resultSet); } catch (err) { logger.error(TAG, 'query result error:' + JSON.stringify(err)); return []; } }
- 创建任务池(taskpool)为数据库操作提供一个多线程的运行环境,将创建好的任务(新增、删除、修改、查询操作)放入taskpool内部任务队列,在子线程中实现数据库增删改查的任务,以此防止阻塞主线程。执行完成后,将结果回调至主线程,从而在主线程中更新数据源和用户界面。这样做不仅提升了应用的响应速度,还确保了用户交互的流畅性。以下代码以查询为例:(注:任务不会立即执行,而是等待分发到工作线程执行。)源码参考
// queryItem函数调用 需使用装饰器@Concurrent
@Concurrent
async function queryItem(context: common.Context): Promise<Array<Contact>> {
return await DatabaseConnection.getInstance().query(context);
}
export async function taskPoolExecuteQuery(context: common.Context): Promise<Array<Contact>> {
try {
let task: taskPool.Task = new taskPool.Task(queryItem, context); // queryItem函数调用 需使用装饰器@Concurrent
let result: Array<Contact> = await taskPool.execute(task) as Array<Contact>;
return result;
} catch (err) {
logger.error(TAG, 'query error:' + JSON.stringify(err));
return [];
}
}
-
在taskpool线程中操作关系型数据库方法的调用,将结果回调至主线程,在回调中来操作数据源。源码参考
// 单条数据插入操作 taskPoolExecuteInsert(context, this.result).then(() => { DynamicsRouter.popAppRouter(); // 数据库插入成功后 操作列表数据源回调 this.addCallback(this.result); }); // 数据删除操作 taskPoolExecuteDelete(context, this.contact).then(() => { if (this.sourceData) { // 数据库删除成功后 操作列表数据源 DynamicsRouter.popAppRouter(); this.deleteCallback(this.sourceData); } // 更新数据操作 taskPoolExecuteUpdate(context, this.result).then(() => { DynamicsRouter.popAppRouter(); // 数据库更新成功后 操作列表数据源回调 this.editCallback(this.result); }); // 数据查询操作 queryRDB() { taskPoolExecuteQuery(context).then((contact: Array<Contact>) => { this.dataArray = contact.reduce((accumulator, item) => { // 如果类别不存在,则创建一个新的数组 if (!accumulator[item.category]) { accumulator[item.category] = []; } // 将当前项添加到相应类别的数组中 accumulator[item.category].push(item); return accumulator; }, {} as Record<string, Contact[]>); // 清空类别数组 this.categoryArray = []; // 使用 Object.entries() 遍历键值对 Object.entries(this.dataArray).forEach(data => { let categoryContact: CategoryContact = { category: data[0], itemsContact: data[1] } this.categoryArray.push(data[0]); this.sourceArray.pushData(categoryContact); }); }); }
高性能知识点
本示例使用了LazyForEach 进行数据懒加载,LazyForEach懒加载可以通过设置cachedCount属性来指定缓存数量,同时搭配组件复用 能力以达到性能最优效果。
工程结构&模块类型
operaterdbintaskpool // har类型
|---constant
| |---CommonConstant.ets // 常量
| |---RdbConstant.ets // Rdb常量
|---model
| |---Contact.ets // Contact数据结构
| |---DataSource.ets // 解析JSON数据
| |---DataSource.ets // 列表数据模型
|---view
| |---AddressBookDetail.ets // 通讯录详情页
| |---AddressBookEdit.ets // 通讯录编辑和新增页
| |---AddressBookList.ets // 通讯录列表页
| |---DatabaseConnection.ets // 数据库相关操作
| |---OpetateRDBTaskPool.ets // 主页面
| |---TaskPool.ets // TaskPool线程

更多推荐
所有评论(0)