HarmonyOS APP进程间通信:DataShare与DataAbility
【摘要】 进程间通信:DataShare与DataAbility数据跨进程共享,让协作成为可能 一、背景与动机:为什么需要跨进程数据共享? 1.1 进程隔离的挑战鸿蒙应用通常运行在独立进程中,内存相互隔离。但有些场景需要跨进程共享数据:通讯录共享:多个应用访问同一份通讯录数据媒体库共享:相册应用、编辑应用共享媒体文件设置同步:系统设置被多个应用读取账号信息:登录状态在多个应用间同步// ❌ 直接访问...
进程间通信:DataShare与DataAbility
数据跨进程共享,让协作成为可能
一、背景与动机:为什么需要跨进程数据共享?
1.1 进程隔离的挑战
鸿蒙应用通常运行在独立进程中,内存相互隔离。但有些场景需要跨进程共享数据:
- 通讯录共享:多个应用访问同一份通讯录数据
- 媒体库共享:相册应用、编辑应用共享媒体文件
- 设置同步:系统设置被多个应用读取
- 账号信息:登录状态在多个应用间同步
// ❌ 直接访问?不可能
// 进程A
const contacts = getContacts() // 通讯录数据在进程A
// 进程B
const contacts = ??? // 无法直接访问进程A的数据
// ✅ 使用DataShare
// 进程A:提供数据
DataShareProvider提供通讯录数据
// 进程B:访问数据
const contacts = DataShareHelper.query(contactsUri)
1.2 DataShare vs DataAbility
鸿蒙提供了两种数据共享方式:
| 特性 | DataAbility(旧) | DataShare(新) |
|---|---|---|
| API版本 | API 6-8 | API 9+ |
| 性能 | 较低 | 更高 |
| 功能 | 基础CRUD | CRUD + 批量 + 观察者 |
| 权限控制 | 简单 | 细粒度 |
| 推荐度 | 已废弃 | 推荐 |

1.3 DataShare架构

二、核心原理:DataShare工作机制
2.1 URI标识
DataShare使用URI来标识数据资源,格式如下:
datashare:///com.example.provider/table_name
datashare://:协议头com.example.provider:数据提供者的bundleNametable_name:数据表名或资源路径
// URI示例
const CONTACTS_URI = 'datashare:///com.example.contacts/contacts'
const CONTACT_URI = 'datashare:///com.example.contacts/contacts/123' // 特定记录
const MEDIA_URI = 'datashare:///com.example.media/images'
2.2 DataShareProvider
数据提供者需要继承DataShareProvider,实现数据操作方法:
// DataShareProvider核心方法
abstract class DataShareProvider {
// 查询数据
abstract query(uri: string, predicates: DataSharePredicates): Array
// 插入数据
abstract insert(uri: string, value: ValuesBucket): number
// 更新数据
abstract update(uri: string, value: ValuesBucket, predicates: DataSharePredicates): number
// 删除数据
abstract delete(uri: string, predicates: DataSharePredicates): number
// 批量插入
batchInsert(uri: string, values: ValuesBucket[]): number
// 获取类型
getType(uri: string): string
// 打开文件
openFile(uri: string, mode: string): number
}
2.3 DataShareHelper
数据消费者使用DataShareHelper访问数据:
// DataShareHelper核心方法
class DataShareHelper {
// 查询
query(uri: string, columns: string[], predicates: DataSharePredicates): DataShareResultSet
// 插入
insert(uri: string, value: ValuesBucket): number
// 更新
update(uri: string, value: ValuesBucket, predicates: DataSharePredicates): number
// 删除
delete(uri: string, predicates: DataSharePredicates): number
// 注册观察者
registerObserver(uri: string, observer: DataObserver): void
// 注销观察者
unregisterObserver(uri: string, observer: DataObserver): void
}
2.4 数据流向
sequenceDiagram
participant Consumer as 数据消费者
participant Helper as DataShareHelper
participant Manager as DataShareManager
participant Provider as DataShareProvider
participant Storage as 数据存储
Consumer->>Helper: query(uri, predicates)
Helper->>Manager: 请求URI
Manager->>Manager: 解析bundleName
Manager->>Manager: 检查权限
alt 权限不足
Manager-->>Helper: 抛出权限异常
Helper-->>Consumer: Error
else 权限通过
Manager->>Provider: 路由到Provider
Provider->>Storage: 查询数据
Storage-->>Provider: 返回结果
Provider-->>Manager: 返回数据
Manager-->>Helper: 返回结果集
Helper-->>Consumer: DataShareResultSet
end
classDef primary fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef warning fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef success fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
class Consumer,Storage primary
class Helper,Manager warning
class Provider success
三、代码实战:实现通讯录共享
3.1 数据提供者:DataShareProvider
// ContactsProvider.ets
import { DataShareProvider, DataSharePredicates, ValuesBucket, DataShareResultSet } from '@kit.ArkData'
import relationalStore from '@ohos.data.relationalStore'
import hilog from '@ohos.hilog'
const TAG = 'ContactsProvider'
const DOMAIN = 0xFF00
/**
* 通讯录数据提供者
* 向其他应用提供通讯录数据
*/
export default class ContactsProvider extends DataShareProvider {
// 数据库对象
private rdbStore: relationalStore.RdbStore = null
// 表名
private static readonly TABLE_NAME = 'contacts'
// URI匹配码
private static readonly CONTACTS = 1
private static readonly CONTACT_ID = 2
/**
* 初始化数据库
*/
async initialize(context: Context): Promise<void> {
const config: relationalStore.StoreConfig = {
name: 'Contacts.db',
securityLevel: relationalStore.SecurityLevel.S1
}
try {
this.rdbStore = await relationalStore.getRdbStore(context, config)
// 创建表
const sql = `
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
phone TEXT,
email TEXT,
avatar TEXT,
created_time INTEGER,
updated_time INTEGER
)
`
await this.rdbStore.executeSql(sql)
hilog.info(DOMAIN, TAG, 'Database initialized')
} catch (err) {
hilog.error(DOMAIN, TAG, `Init failed: ${err.message}`)
}
}
/**
* 查询数据
*/
async query(
uri: string,
predicates: DataSharePredicates,
columns: string[]
): Promise<DataShareResultSet> {
hilog.info(DOMAIN, TAG, `Query: ${uri}`)
// 解析URI
const uriMatch = this.matchUri(uri)
if (uriMatch === ContactsProvider.CONTACTS) {
// 查询所有通讯录
return await this.queryContacts(predicates, columns)
} else if (uriMatch === ContactsProvider.CONTACT_ID) {
// 查询特定联系人
const id = this.extractId(uri)
return await this.queryContactById(id, columns)
}
return null
}
/**
* 查询所有通讯录
*/
private async queryContacts(
predicates: DataSharePredicates,
columns: string[]
): Promise<DataShareResultSet> {
// 构建查询条件
const querySql = this.buildQuerySql(predicates, columns)
hilog.info(DOMAIN, TAG, `Query SQL: ${querySql}`)
// 执行查询
const resultSet = await this.rdbStore.querySql(querySql)
// 转换为DataShareResultSet
return this.convertToDataShareResultSet(resultSet)
}
/**
* 查询特定联系人
*/
private async queryContactById(
id: number,
columns: string[]
): Promise<DataShareResultSet> {
const selection = `id = ${id}`
const resultSet = await this.rdbStore.query(selection, columns)
return this.convertToDataShareResultSet(resultSet)
}
/**
* 插入数据
*/
async insert(uri: string, value: ValuesBucket): Promise<number> {
hilog.info(DOMAIN, TAG, `Insert: ${uri}`)
// 添加时间戳
value['created_time'] = Date.now()
value['updated_time'] = Date.now()
// 插入数据
const rowId = await this.rdbStore.insert(ContactsProvider.TABLE_NAME, value)
hilog.info(DOMAIN, TAG, `Inserted row: ${rowId}`)
// 通知观察者数据变化
this.notifyDataChange(uri)
return rowId
}
/**
* 批量插入
*/
async batchInsert(uri: string, values: ValuesBucket[]): Promise<number> {
hilog.info(DOMAIN, TAG, `Batch insert: ${values.length} records`)
const now = Date.now()
// 添加时间戳
for (const value of values) {
value['created_time'] = now
value['updated_time'] = now
}
// 批量插入
const count = await this.rdbStore.batchInsert(ContactsProvider.TABLE_NAME, values)
hilog.info(DOMAIN, TAG, `Batch inserted: ${count} rows`)
// 通知观察者
this.notifyDataChange(uri)
return count
}
/**
* 更新数据
*/
async update(
uri: string,
value: ValuesBucket,
predicates: DataSharePredicates
): Promise<number> {
hilog.info(DOMAIN, TAG, `Update: ${uri}`)
// 更新时间戳
value['updated_time'] = Date.now()
// 构建条件
const whereClause = this.buildWhereClause(predicates)
const whereArgs = this.buildWhereArgs(predicates)
// 执行更新
const count = await this.rdbStore.update(
value,
ContactsProvider.TABLE_NAME,
whereClause,
whereArgs
)
hilog.info(DOMAIN, TAG, `Updated: ${count} rows`)
// 通知观察者
this.notifyDataChange(uri)
return count
}
/**
* 删除数据
*/
async delete(uri: string, predicates: DataSharePredicates): Promise<number> {
hilog.info(DOMAIN, TAG, `Delete: ${uri}`)
// 构建条件
const whereClause = this.buildWhereClause(predicates)
const whereArgs = this.buildWhereArgs(predicates)
// 执行删除
const count = await this.rdbStore.delete(
ContactsProvider.TABLE_NAME,
whereClause,
whereArgs
)
hilog.info(DOMAIN, TAG, `Deleted: ${count} rows`)
// 通知观察者
this.notifyDataChange(uri)
return count
}
/**
* 匹配URI
*/
private matchUri(uri: string): number {
// 解析URI路径
// datashare:///com.example.contacts/contacts -> CONTACTS
// datashare:///com.example.contacts/contacts/123 -> CONTACT_ID
const segments = uri.split('/').filter(s => s.length > 0)
if (segments.length === 3 && segments[2] === 'contacts') {
return ContactsProvider.CONTACTS
} else if (segments.length === 4 && segments[2] === 'contacts') {
return ContactsProvider.CONTACT_ID
}
return -1
}
/**
* 从URI提取ID
*/
private extractId(uri: string): number {
const segments = uri.split('/')
return parseInt(segments[segments.length - 1])
}
/**
* 构建查询SQL
*/
private buildQuerySql(predicates: DataSharePredicates, columns: string[]): string {
let sql = `SELECT ${columns.length > 0 ? columns.join(', ') : '*'} FROM ${ContactsProvider.TABLE_NAME}`
// 添加WHERE条件
const whereClause = this.buildWhereClause(predicates)
if (whereClause) {
sql += ` WHERE ${whereClause}`
}
// 添加ORDER BY
if (predicates.getOrderbyString()) {
sql += ` ORDER BY ${predicates.getOrderbyString()}`
}
// 添加LIMIT
if (predicates.getLimit()) {
sql += ` LIMIT ${predicates.getLimit()}`
}
return sql
}
/**
* 构建WHERE子句
*/
private buildWhereClause(predicates: DataSharePredicates): string {
// 从predicates构建WHERE条件
// 简化实现,实际需要完整解析predicates
return predicates.getWhereClause() ?? ''
}
/**
* 构建WHERE参数
*/
private buildWhereArgs(predicates: DataSharePredicates): string[] {
return predicates.getWhereArgs() ?? []
}
/**
* 转换结果集
*/
private convertToDataShareResultSet(
resultSet: relationalStore.ResultSet
): DataShareResultSet {
// 将RdbResultSet转换为DataShareResultSet
// 简化实现
return resultSet as unknown as DataShareResultSet
}
/**
* 通知数据变化
*/
private notifyDataChange(uri: string): void {
// 调用父类方法通知观察者
// this.notifyChange(uri)
hilog.info(DOMAIN, TAG, `Data changed: ${uri}`)
}
}
3.2 配置DataShareExtensionAbility
// ContactsDataShare.ets
import { DataShareExtensionAbility } from '@kit.ArkData'
import ContactsProvider from './ContactsProvider'
import hilog from '@ohos.hilog'
const TAG = 'ContactsDataShare'
const DOMAIN = 0xFF00
/**
* 通讯录DataShare扩展能力
* 在module.json5中配置
*/
export default class ContactsDataShare extends DataShareExtensionAbility {
private provider: ContactsProvider = null
/**
* 创建DataShareProvider
*/
onCreate(want: Want): DataShareProvider {
hilog.info(DOMAIN, TAG, 'ContactsDataShare onCreate')
// 创建Provider实例
this.provider = new ContactsProvider()
// 初始化数据库
this.provider.initialize(this.context)
return this.provider
}
/**
* 销毁
*/
onDestroy(): void {
hilog.info(DOMAIN, TAG, 'ContactsDataShare onDestroy')
this.provider = null
}
}
// module.json5配置
{
"module": {
"extensionAbilities": [
{
"name": "ContactsDataShare",
"srcEntry": "./ets/ContactsDataShare.ets",
"type": "dataShare",
"metadata": [
{
"name": "ohos.extension.dataShare",
"resource": "$profile:data_share_config"
}
],
"readPermission": "ohos.permission.READ_CONTACTS",
"writePermission": "ohos.permission.WRITE_CONTACTS"
}
]
}
}
3.3 数据消费者:DataShareHelper
// ContactsConsumer.ets
import { dataShare, DataSharePredicates, ValuesBucket } from '@kit.ArkData'
import hilog from '@ohos.hilog'
const TAG = 'ContactsConsumer'
const DOMAIN = 0xFF00
/**
* 通讯录URI
*/
const CONTACTS_URI = 'datashare:///com.example.contacts/contacts'
/**
* 通讯录消费者
* 访问其他应用提供的通讯录数据
*/
export class ContactsConsumer {
private dataShareHelper: dataShare.DataShareHelper = null
/**
* 初始化DataShareHelper
*/
async initialize(context: Context): Promise<void> {
try {
// 创建DataShareHelper
this.dataShareHelper = await dataShare.createDataShareHelper(context, CONTACTS_URI)
hilog.info(DOMAIN, TAG, 'DataShareHelper created')
} catch (err) {
hilog.error(DOMAIN, TAG, `Init failed: ${err.message}`)
}
}
/**
* 查询所有联系人
*/
async queryAllContacts(): Promise<Contact[]> {
if (!this.dataShareHelper) {
hilog.error(DOMAIN, TAG, 'DataShareHelper not initialized')
return []
}
try {
// 创建查询条件
const predicates = new DataSharePredicates()
predicates.orderByAsc('name') // 按姓名排序
// 指定查询列
const columns = ['id', 'name', 'phone', 'email', 'avatar']
// 执行查询
const resultSet = await this.dataShareHelper.query(CONTACTS_URI, predicates, columns)
// 解析结果
const contacts: Contact[] = []
if (resultSet) {
while (resultSet.goToNextRow()) {
const contact: Contact = {
id: resultSet.getLong(resultSet.getColumnIndex('id')),
name: resultSet.getString(resultSet.getColumnIndex('name')),
phone: resultSet.getString(resultSet.getColumnIndex('phone')),
email: resultSet.getString(resultSet.getColumnIndex('email')),
avatar: resultSet.getString(resultSet.getColumnIndex('avatar'))
}
contacts.push(contact)
}
resultSet.close()
}
hilog.info(DOMAIN, TAG, `Queried ${contacts.length} contacts`)
return contacts
} catch (err) {
hilog.error(DOMAIN, TAG, `Query failed: ${err.message}`)
return []
}
}
/**
* 查询特定联系人
*/
async queryContactById(id: number): Promise<Contact | null> {
const uri = `${CONTACTS_URI}/${id}`
try {
const predicates = new DataSharePredicates()
const columns = ['id', 'name', 'phone', 'email', 'avatar']
const resultSet = await this.dataShareHelper.query(uri, predicates, columns)
if (resultSet && resultSet.goToNextRow()) {
const contact: Contact = {
id: resultSet.getLong(resultSet.getColumnIndex('id')),
name: resultSet.getString(resultSet.getColumnIndex('name')),
phone: resultSet.getString(resultSet.getColumnIndex('phone')),
email: resultSet.getString(resultSet.getColumnIndex('email')),
avatar: resultSet.getString(resultSet.getColumnIndex('avatar'))
}
resultSet.close()
return contact
}
return null
} catch (err) {
hilog.error(DOMAIN, TAG, `Query by id failed: ${err.message}`)
return null
}
}
/**
* 搜索联系人
*/
async searchContacts(keyword: string): Promise<Contact[]> {
try {
const predicates = new DataSharePredicates()
// 模糊搜索:name LIKE '%keyword%' OR phone LIKE '%keyword%'
predicates.beginWrap()
.like('name', `%${keyword}%`)
.or()
.like('phone', `%${keyword}%`)
predicates.endWrap()
predicates.orderByAsc('name')
const columns = ['id', 'name', 'phone', 'email', 'avatar']
const resultSet = await this.dataShareHelper.query(CONTACTS_URI, predicates, columns)
const contacts: Contact[] = []
if (resultSet) {
while (resultSet.goToNextRow()) {
const contact: Contact = {
id: resultSet.getLong(resultSet.getColumnIndex('id')),
name: resultSet.getString(resultSet.getColumnIndex('name')),
phone: resultSet.getString(resultSet.getColumnIndex('phone')),
email: resultSet.getString(resultSet.getColumnIndex('email')),
avatar: resultSet.getString(resultSet.getColumnIndex('avatar'))
}
contacts.push(contact)
}
resultSet.close()
}
return contacts
} catch (err) {
hilog.error(DOMAIN, TAG, `Search failed: ${err.message}`)
return []
}
}
/**
* 添加联系人
*/
async addContact(contact: Omit<Contact, 'id'>): Promise<number> {
try {
const value: ValuesBucket = {
'name': contact.name,
'phone': contact.phone ?? '',
'email': contact.email ?? '',
'avatar': contact.avatar ?? ''
}
const rowId = await this.dataShareHelper.insert(CONTACTS_URI, value)
hilog.info(DOMAIN, TAG, `Contact added: ${rowId}`)
return rowId
} catch (err) {
hilog.error(DOMAIN, TAG, `Add contact failed: ${err.message}`)
return -1
}
}
/**
* 更新联系人
*/
async updateContact(id: number, contact: Partial<Contact>): Promise<boolean> {
try {
const uri = `${CONTACTS_URI}/${id}`
const value: ValuesBucket = {}
if (contact.name) value['name'] = contact.name
if (contact.phone) value['phone'] = contact.phone
if (contact.email) value['email'] = contact.email
if (contact.avatar) value['avatar'] = contact.avatar
const predicates = new DataSharePredicates()
predicates.equalTo('id', id)
const count = await this.dataShareHelper.update(uri, value, predicates)
hilog.info(DOMAIN, TAG, `Contact updated: ${count} rows`)
return count > 0
} catch (err) {
hilog.error(DOMAIN, TAG, `Update contact failed: ${err.message}`)
return false
}
}
/**
* 删除联系人
*/
async deleteContact(id: number): Promise<boolean> {
try {
const uri = `${CONTACTS_URI}/${id}`
const predicates = new DataSharePredicates()
predicates.equalTo('id', id)
const count = await this.dataShareHelper.delete(uri, predicates)
hilog.info(DOMAIN, TAG, `Contact deleted: ${count} rows`)
return count > 0
} catch (err) {
hilog.error(DOMAIN, TAG, `Delete contact failed: ${err.message}`)
return false
}
}
/**
* 注册数据变化观察者
*/
registerObserver(callback: () => void): void {
if (this.dataShareHelper) {
const observer: dataShare.DataObserver = {
onChange: (uri: string) => {
hilog.info(DOMAIN, TAG, `Data changed: ${uri}`)
callback()
}
}
this.dataShareHelper.registerObserver(CONTACTS_URI, observer)
hilog.info(DOMAIN, TAG, 'Observer registered')
}
}
/**
* 销毁
*/
destroy(): void {
if (this.dataShareHelper) {
// 注销所有观察者
this.dataShareHelper.unregisterObserver(CONTACTS_URI, null)
hilog.info(DOMAIN, TAG, 'DataShareHelper destroyed')
}
}
}
/**
* 联系人数据结构
*/
interface Contact {
id: number
name: string
phone?: string
email?: string
avatar?: string
}
3.4 在UI中使用
// ContactsPage.ets
import { ContactsConsumer } from './ContactsConsumer'
import hilog from '@ohos.hilog'
const TAG = 'ContactsPage'
const DOMAIN = 0xFF00
@Entry
@Component
struct ContactsPage {
@State contacts: Contact[] = []
@State searchText: string = ''
@State isLoading: boolean = false
private contactsConsumer: ContactsConsumer = new ContactsConsumer()
async aboutToAppear() {
// 初始化
await this.contactsConsumer.initialize(getContext(this))
// 注册数据变化观察者
this.contactsConsumer.registerObserver(() => {
// 数据变化时刷新列表
this.refreshContacts()
})
// 加载联系人
await this.refreshContacts()
}
aboutToDisappear() {
this.contactsConsumer.destroy()
}
/**
* 刷新联系人列表
*/
async refreshContacts(): Promise<void> {
this.isLoading = true
try {
if (this.searchText) {
this.contacts = await this.contactsConsumer.searchContacts(this.searchText)
} else {
this.contacts = await this.contactsConsumer.queryAllContacts()
}
} finally {
this.isLoading = false
}
}
/**
* 添加新联系人
*/
async addNewContact(): Promise<void> {
const newContact = {
name: '新联系人',
phone: '13800138000'
}
const id = await this.contactsConsumer.addContact(newContact)
if (id > 0) {
await this.refreshContacts()
}
}
/**
* 删除联系人
*/
async deleteContact(id: number): Promise<void> {
const success = await this.contactsConsumer.deleteContact(id)
if (success) {
await this.refreshContacts()
}
}
build() {
Column() {
// 搜索栏
Row() {
TextInput({ placeholder: '搜索联系人' })
.width('70%')
.onChange((value) => {
this.searchText = value
})
Button('搜索')
.onClick(() => {
this.refreshContacts()
})
}
.width('100%')
.padding(10)
// 联系人列表
if (this.isLoading) {
LoadingProgress()
.width(50)
.height(50)
} else {
List() {
ForEach(this.contacts, (contact: Contact) => {
ListItem() {
Row() {
// 头像
if (contact.avatar) {
Image(contact.avatar)
.width(50)
.height(50)
.borderRadius(25)
} else {
Text(contact.name.charAt(0))
.width(50)
.height(50)
.borderRadius(25)
.backgroundColor('#e0e0e0')
.textAlign(TextAlign.Center)
}
// 信息
Column() {
Text(contact.name)
.fontSize(16)
.fontWeight(FontWeight.Bold)
if (contact.phone) {
Text(contact.phone)
.fontSize(14)
.fontColor('#666666')
}
}
.alignItems(HorizontalAlign.Start)
.margin({ left: 10 })
.layoutWeight(1)
// 删除按钮
Button('删除')
.onClick(() => {
this.deleteContact(contact.id)
})
}
.width('100%')
.padding(10)
}
})
}
.width('100%')
.layoutWeight(1)
}
// 添加按钮
Button('添加联系人')
.width('90%')
.margin(10)
.onClick(() => {
this.addNewContact()
})
}
.width('100%')
.height('100%')
}
}
四、踩坑与注意事项
4.1 坑一:权限配置错误
问题:权限配置不正确,导致访问失败。
// ❌ 缺少权限声明
// module.json5中未配置权限
// ✅ 正确配置权限
// module.json5
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.READ_CONTACTS",
"reason": "读取通讯录",
"usedScene": {
"abilities": ["MainAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.WRITE_CONTACTS",
"reason": "修改通讯录",
"usedScene": {
"abilities": ["MainAbility"],
"when": "inuse"
}
}
]
}
}
4.2 坑二:URI格式错误
问题:URI格式不正确,无法找到Provider。
// ❌ URI格式错误
const uri1 = 'content://com.example.contacts' // 协议头错误
const uri2 = 'datashare://com.example.contacts/contacts' // 少了一个斜杠
// ✅ 正确的URI格式
const uri = 'datashare:///com.example.contacts/contacts'
// ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^
// 协议头 bundleName 路径
// 动态构建URI
function buildContactUri(id?: number): string {
const baseUri = 'datashare:///com.example.contacts/contacts'
return id ? `${baseUri}/${id}` : baseUri
}
4.3 坑三:结果集未关闭
问题:查询结果集未关闭,导致资源泄漏。
// ❌ 结果集未关闭
async queryContacts() {
const resultSet = await helper.query(uri, predicates, columns)
while (resultSet.goToNextRow()) {
// 处理数据
}
// 没有关闭!
}
// ✅ 使用try-finally确保关闭
async queryContacts() {
let resultSet = null
try {
resultSet = await helper.query(uri, predicates, columns)
const contacts = []
while (resultSet.goToNextRow()) {
// 处理数据
contacts.push(...)
}
return contacts
} finally {
if (resultSet) {
resultSet.close()
}
}
}
4.4 坑四:跨应用访问权限
问题:访问其他应用的数据时权限不足。
// ✅ 检查权限并处理
async queryWithPermissionCheck() {
try {
const resultSet = await helper.query(uri, predicates, columns)
// 处理结果
} catch (err) {
if (err.code === 201 || err.code === 202) {
// 权限不足
hilog.error(DOMAIN, TAG, 'Permission denied')
// 提示用户授权
this.requestPermission()
} else {
hilog.error(DOMAIN, TAG, `Query failed: ${err.message}`)
}
}
}
// 请求权限
async requestPermission(): Promise<void> {
// 使用abilityAccessCtrl请求权限
// ...
}
五、HarmonyOS 6适配指南
5.1 API变更
| 变更项 | HarmonyOS 5 | HarmonyOS 6 |
|---|---|---|
| 导入方式 | @ohos.data.dataShare |
@kit.ArkData |
| 创建Helper | dataShare.createDataShareHelper |
同上 |
| 结果集类型 | DataShareResultSet |
同上 |
| 批量操作 | batchInsert |
新增batchUpdate、batchDelete |
5.2 新增功能
// HarmonyOS 6新增:批量更新
async batchUpdate(contacts: Contact[]): Promise<number> {
const values: ValuesBucket[] = contacts.map(c => ({
'id': c.id,
'name': c.name,
'phone': c.phone,
'email': c.email
}))
return await this.dataShareHelper.batchUpdate(CONTACTS_URI, values)
}
// HarmonyOS 6新增:事务支持
async insertWithTransaction(contacts: Contact[]): Promise<void> {
// 开始事务
await this.dataShareHelper.beginTransaction()
try {
for (const contact of contacts) {
await this.dataShareHelper.insert(CONTACTS_URI, contact)
}
// 提交事务
await this.dataShareHelper.commit()
} catch (err) {
// 回滚事务
await this.dataShareHelper.rollback()
throw err
}
}
// HarmonyOS 6新增:分页查询
async queryPaged(page: number, pageSize: number): Promise<Contact[]> {
const predicates = new DataSharePredicates()
predicates.limitAs(pageSize)
predicates.offsetAs((page - 1) * pageSize)
predicates.orderByAsc('name')
const resultSet = await this.dataShareHelper.query(CONTACTS_URI, predicates, columns)
// ...
}
六、总结
6.1 核心要点回顾

6.2 最佳实践清单
- [ ] 正确配置权限
- [ ] 使用正确的URI格式
- [ ] 及时关闭结果集
- [ ] 处理权限不足的情况
- [ ] 使用观察者监听数据变化
- [ ] 批量操作使用batch方法
- [ ] 复杂操作使用事务
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)