#跟着坚果学鸿蒙# HarmonyOS 5 访问DataAbility开发指南:从基础到实践
·
一、DataAbility基础概念
在HarmonyOS 5中,DataAbility是一种特殊类型的Ability,主要用于提供数据访问服务。它允许应用以统一的方式访问和操作数据,无论数据存储在SQLite数据库、文件系统还是其他位置。
DataAbility的核心特点包括:
- 数据抽象:统一不同数据源的访问接口
- 跨进程访问:支持应用间安全的数据共享
- 标准化操作:提供CRUD(创建、读取、更新、删除)的标准接口
二、DataAbilityHelper介绍
DataAbilityHelper是HarmonyOS 5中用于与DataAbility交互的工具类,它封装了与DataAbility通信的细节,开发者可以通过它执行各种数据操作。
主要功能包括:
- 插入(insert)
- 删除(delete)
- 更新(update)
- 查询(query)
- 批量操作(executeBatch)
三、完整示例:联系人管理应用
下面我们通过一个完整的联系人管理示例,演示如何使用DataAbilityHelper操作DataAbility。
1. 创建DataAbility
首先需要创建一个DataAbility来管理联系人数据:
// ContactDataAbility.ts
import relationalStore from '@ohos.data.relationalStore';
import dataAbility from '@ohos.ability.dataAbility';
import window from '@ohos.window';
const DB_NAME = 'contact_db'
const TABLE_NAME = 'contact'
const DB_VERSION = 1
let store: relationalStore.RdbStore | null = null
export default class ContactDataAbility extends dataAbility.DataAbility {
async onInit(want: Want): Promise<void> {
console.info('ContactDataAbility onInit')
// 初始化数据库
const config: relationalStore.StoreConfig = {
name: DB_NAME,
securityLevel: relationalStore.SecurityLevel.S1
}
try {
store = await relationalStore.getRdbStore(this.context, config)
await this.initTable()
} catch (err) {
console.error(`Failed to init RdbStore. Code:${err.code}, message:${err.message}`)
}
}
private async initTable(): Promise<void> {
// 创建联系人表
const sql = `CREATE TABLE IF NOT EXISTS ${TABLE_NAME} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
phone TEXT NOT NULL,
email TEXT
)`
await store.executeSql(sql)
console.info('Create table success')
}
// 插入联系人
async insert(uri: string, valueBucket: ValuesBucket): Promise<number> {
console.info('ContactDataAbility insert')
if (!store) {
console.error('RdbStore is not initialized')
return -1
}
try {
const id = await store.insert(TABLE_NAME, valueBucket)
console.info(`Insert contact success, id:${id}`)
return id
} catch (err) {
console.error(`Failed to insert contact. Code:${err.code}, message:${err.message}`)
return -1
}
}
// 查询联系人
async query(uri: string, columns: Array<string>, predicates: dataAbility.DataAbilityPredicates): Promise<ResultSet> {
console.info('ContactDataAbility query')
if (!store) {
console.error('RdbStore is not initialized')
return null
}
try {
const predicatesObj = predicates.getRdbPredicates(TABLE_NAME)
const resultSet = await store.query(predicatesObj, columns)
console.info('Query contact success')
return resultSet
} catch (err) {
console.error(`Failed to query contact. Code:${err.code}, message:${err.message}`)
return null
}
}
// 更新联系人
async update(uri: string, valueBucket: ValuesBucket, predicates: dataAbility.DataAbilityPredicates): Promise<number> {
console.info('ContactDataAbility update')
if (!store) {
console.error('RdbStore is not initialized')
return -1
}
try {
const predicatesObj = predicates.getRdbPredicates(TABLE_NAME)
const rowsAffected = await store.update(valueBucket, predicatesObj)
console.info(`Update contact success, rows affected:${rowsAffected}`)
return rowsAffected
} catch (err) {
console.error(`Failed to update contact. Code:${err.code}, message:${err.message}`)
return -1
}
}
// 删除联系人
async delete(uri: string, predicates: dataAbility.DataAbilityPredicates): Promise<number> {
console.info('ContactDataAbility delete')
if (!store) {
console.error('RdbStore is not initialized')
return -1
}
try {
const predicatesObj = predicates.getRdbPredicates(TABLE_NAME)
const rowsAffected = await store.delete(predicatesObj)
console.info(`Delete contact success, rows affected:${rowsAffected}`)
return rowsAffected
} catch (err) {
console.error(`Failed to delete contact. Code:${err.code}, message:${err.message}`)
return -1
}
}
}
2. 配置DataAbility
在module.json5中注册DataAbility:
{
"module": {
"abilities": [
{
"name": "ContactDataAbility",
"type": "data",
"uri": "dataability://com.example.contact.ContactDataAbility",
"label": "Contact Data Ability",
"icon": "$media:icon",
"visible": true,
"exported": true
}
]
}
}
3. 使用DataAbilityHelper访问数据
创建UI界面并使用DataAbilityHelper操作数据:
// ContactManager.ets
import dataAbility from '@ohos.ability.dataAbility';
import relationalStore from '@ohos.data.relationalStore';
import promptAction from '@ohos.promptAction';
@Entry
@Component
struct ContactManager {
@State contacts: Array<Contact> = []
private dataAbilityHelper: dataAbility.DataAbilityHelper | null = null
private readonly CONTACT_URI = 'dataability://com.example.contact.ContactDataAbility/contact'
aboutToAppear() {
// 创建DataAbilityHelper
this.dataAbilityHelper = dataAbility.createDataAbilityHelper(this.context)
this.loadContacts()
}
// 加载联系人列表
private loadContacts() {
if (!this.dataAbilityHelper) return
const predicates = new dataAbility.DataAbilityPredicates()
predicates.orderByAsc('name')
this.dataAbilityHelper.query(this.CONTACT_URI, ['id', 'name', 'phone', 'email'], predicates)
.then((resultSet: relationalStore.ResultSet) => {
this.contacts = []
while (resultSet.goToNextRow()) {
this.contacts.push({
id: resultSet.getLong(resultSet.getColumnIndex('id')),
name: resultSet.getString(resultSet.getColumnIndex('name')),
phone: resultSet.getString(resultSet.getColumnIndex('phone')),
email: resultSet.getString(resultSet.getColumnIndex('email'))
})
}
resultSet.close()
})
.catch(err => {
promptAction.showToast({ message: `查询失败: ${err.message}` })
})
}
// 添加联系人
private addContact(name: string, phone: string, email: string) {
if (!this.dataAbilityHelper) return
const valueBucket = {
'name': name,
'phone': phone,
'email': email || ''
}
this.dataAbilityHelper.insert(this.CONTACT_URI, valueBucket)
.then(id => {
promptAction.showToast({ message: '添加成功' })
this.loadContacts()
})
.catch(err => {
promptAction.showToast({ message: `添加失败: ${err.message}` })
})
}
// 更新联系人
private updateContact(id: number, name: string, phone: string, email: string) {
if (!this.dataAbilityHelper) return
const valueBucket = {
'name': name,
'phone': phone,
'email': email || ''
}
const predicates = new dataAbility.DataAbilityPredicates()
predicates.equalTo('id', id)
this.dataAbilityHelper.update(this.CONTACT_URI, valueBucket, predicates)
.then(rowsAffected => {
if (rowsAffected > 0) {
promptAction.showToast({ message: '更新成功' })
this.loadContacts()
} else {
promptAction.showToast({ message: '未找到联系人' })
}
})
.catch(err => {
promptAction.showToast({ message: `更新失败: ${err.message}` })
})
}
// 删除联系人
private deleteContact(id: number) {
if (!this.dataAbilityHelper) return
const predicates = new dataAbility.DataAbilityPredicates()
predicates.equalTo('id', id)
this.dataAbilityHelper.delete(this.CONTACT_URI, predicates)
.then(rowsAffected => {
if (rowsAffected > 0) {
promptAction.showToast({ message: '删除成功' })
this.loadContacts()
} else {
promptAction.showToast({ message: '未找到联系人' })
}
})
.catch(err => {
promptAction.showToast({ message: `删除失败: ${err.message}` })
})
}
build() {
Column() {
List({ space: 10 }) {
ForEach(this.contacts, (contact: Contact) => {
ListItem() {
ContactItem({ contact: contact,
onDelete: (id: number) => this.deleteContact(id)
})
}
}, (contact: Contact) => contact.id.toString())
}
.layoutWeight(1)
.width('100%')
Button('添加测试联系人')
.onClick(() => {
this.addContact('测试用户', '13800138000', 'test@example.com')
})
.margin(10)
}
.width('100%')
.height('100%')
.padding(10)
}
}
@Component
struct ContactItem {
@Prop contact: Contact
@Link onDelete: (id: number) => void
@State showDialog: boolean = false
build() {
Column() {
Text(this.contact.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text(`电话: ${this.contact.phone}`)
Text(`邮箱: ${this.contact.email || '无'}`)
Row() {
Button('删除')
.onClick(() => {
this.showDialog = true
})
}
.justifyContent(FlexAlign.End)
.width('100%')
}
.padding(10)
.borderRadius(10)
.backgroundColor(Color.White)
.shadow({ radius: 5, color: '#ccc', offsetX: 2, offsetY: 2 })
// 删除确认对话框
if (this.showDialog) {
DialogComponent({
title: '确认删除',
message: `确定要删除联系人 ${this.contact.name} 吗?`,
onConfirm: () => {
this.onDelete(this.contact.id)
this.showDialog = false
},
onCancel: () => {
this.showDialog = false
}
})
}
}
}
// 对话框组件
@Builder
function DialogComponent(params: {
title: string,
message: string,
onConfirm: () => void,
onCancel: () => void
}) {
Column() {
Text(params.title)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Text(params.message)
.margin({ bottom: 20 })
Row() {
Button('取消')
.onClick(params.onCancel)
.layoutWeight(1)
Button('确定')
.onClick(params.onConfirm)
.layoutWeight(1)
}
.width('100%')
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(10)
}
interface Contact {
id: number
name: string
phone: string
email: string
}
四、DataAbility高级用法
1. 批量操作
DataAbilityHelper提供了executeBatch方法用于执行批量操作:
private batchInsertContacts(contacts: Array<Omit<Contact, 'id'>>) {
if (!this.dataAbilityHelper) return
const operations: Array<dataAbility.DataAbilityOperation> = contacts.map(contact => {
return {
uri: this.CONTACT_URI,
type: dataAbility.OperationType.INSERT,
valuesBucket: {
'name': contact.name,
'phone': contact.phone,
'email': contact.email || ''
}
}
})
this.dataAbilityHelper.executeBatch(this.CONTACT_URI, operations)
.then(results => {
const successCount = results.filter(r => r.count > 0).length
promptAction.showToast({ message: `批量添加成功 ${successCount}/${contacts.length}` })
this.loadContacts()
})
.catch(err => {
promptAction.showToast({ message: `批量添加失败: ${err.message}` })
})
}
2. 文件操作
DataAbility也可以用于文件操作,例如:
// 在DataAbility中实现文件操作
async fileInsert(uri: string, valueBucket: ValuesBucket): Promise<number> {
const fileUri = valueBucket.get('fileUri')
const fileName = valueBucket.get('fileName')
try {
const file = await fs.open(fileUri, fs.OpenMode.READ_ONLY)
const content = await fs.readText(file.fd)
await fs.close(file.fd)
const targetPath = this.context.filesDir + '/' + fileName
const targetFile = await fs.open(targetPath, fs.OpenMode.WRITE_ONLY | fs.OpenMode.CREATE)
await fs.write(targetFile.fd, content)
await fs.close(targetFile.fd)
return 1
} catch (err) {
console.error(`File operation failed: ${err.message}`)
return -1
}
}
// 客户端调用
private saveFile(uri: string, fileName: string) {
const valueBucket = {
'fileUri': uri,
'fileName': fileName
}
this.dataAbilityHelper.insert('dataability://com.example.file.FileDataAbility/file', valueBucket)
.then(result => {
promptAction.showToast({ message: '文件保存成功' })
})
.catch(err => {
promptAction.showToast({ message: `文件保存失败: ${err.message}` })
})
}
五、最佳实践与注意事项
-
性能优化
- 对于批量操作,优先使用executeBatch
- 查询时只获取需要的列
- 使用分页查询大数据集
-
安全考虑
- 验证输入数据
- 使用参数化查询防止SQL注入
- 设置合适的权限控制
-
错误处理
- 检查DataAbilityHelper是否初始化
- 捕获并处理所有可能的异常
- 提供有意义的错误反馈
-
线程管理
- 数据操作应在非UI线程执行
- 使用Promise或async/await处理异步操作
通过本文的介绍和示例,您应该已经掌握了HarmonyOS 5中DataAbility的基本用法和高级技巧。DataAbility提供了一种统一、安全的数据访问方式,是HarmonyOS应用开发中不可或缺的重要组成部分。
更多推荐
所有评论(0)