HarmonyOS APP进程间通信:DataShare与DataAbility

举报
Jack20 发表于 2026/06/19 19:01:07 2026/06/19
【摘要】 进程间通信: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 + 批量 + 观察者
权限控制 简单 细粒度
推荐度 已废弃 推荐

图片.png

1.3 DataShare架构

图片.png

二、核心原理:DataShare工作机制

2.1 URI标识

DataShare使用URI来标识数据资源,格式如下:

datashare:///com.example.provider/table_name
  • datashare://:协议头
  • com.example.provider:数据提供者的bundleName
  • table_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 新增batchUpdatebatchDelete

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 核心要点回顾

图片.png

6.2 最佳实践清单

  • [ ] 正确配置权限
  • [ ] 使用正确的URI格式
  • [ ] 及时关闭结果集
  • [ ] 处理权限不足的情况
  • [ ] 使用观察者监听数据变化
  • [ ] 批量操作使用batch方法
  • [ ] 复杂操作使用事务

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。