HarmonyOS开发:卡片数据共享——DataShare与卡片联动
HarmonyOS开发:卡片数据共享——DataShare与卡片联动
📌 核心要点:FormAbility和UIAbility的上下文是隔离的,多卡片之间也各自独立,DataShare是打通这些数据孤岛的核心桥梁。
背景与动机
你有没有遇到过这种场景:
天气App的UIAbility里刷新了天气数据,但桌面上那张天气卡片还是显示旧数据。为什么?因为UIAbility和FormAbility的上下文是隔离的,UIAbility更新了数据,FormAbility根本不知道。
或者:用户添加了两张天气卡片——一张显示当前天气,一张显示三天预报。UIAbility刷新数据后,只更新了当前天气卡片,三天预报卡片还是旧的。为什么?因为两张卡片是独立的formId,你得一个一个更新。
再或者:你的待办App有"今日待办"和"本周待办"两张卡片,用户在App里完成了一个待办,两张卡片应该同时更新。但你怎么确保两张卡片的数据一致?
这些问题的根源都是——数据孤岛。FormAbility、UIAbility、多张卡片之间,默认是互不相通的。要打通它们,你需要一个共享数据层。
DataShare就是鸿蒙提供的这个共享数据层。它本质上是一个跨进程的数据访问接口,UIAbility写数据,FormAbility读数据,多张卡片共享同一份数据源。
核心原理
数据共享架构
flowchart TB
subgraph 数据写入方
A[UIAbility] -->|写入| D[DataShare<br/>共享数据层]
B[网络推送服务] -->|写入| D
end
subgraph 共享数据层
D --> E[关系型数据库<br/>RDB]
D --> F[键值对缓存]
end
subgraph 数据读取方
D -->|读取| G[FormAbility<br/>卡片A]
D -->|读取| H[FormAbility<br/>卡片B]
D -->|读取| I[FormAbility<br/>卡片C]
end
subgraph 联动更新
G --> J[formProvider.updateForm]
H --> J
I --> J
J --> K[所有卡片同步刷新]
end
classDef writer fill:#E8F5E9,stroke:#2E7D32,color:#1B5E20
classDef share fill:#FFF3E0,stroke:#E65100,color:#BF360C
classDef reader fill:#E3F2FD,stroke:#1565C0,color:#0D47A1
classDef update fill:#FCE4EC,stroke:#C62828,color:#B71C1C
class A,B writer
class D,E,F share
class G,H,I reader
class J,K update
关键点:DataShare是"中间人"——UIAbility负责写数据,FormAbility负责读数据,两者不直接通信。这种解耦架构的好处是:即使UIAbility进程被杀了,DataShare的数据还在,FormAbility照样能读到。
DataShare在卡片中的工作流程
sequenceDiagram
participant UI as UIAbility
participant DS as DataShare
participant FA as FormAbility
participant FP as formProvider
participant Card as 卡片UI
Note over UI,Card: 数据写入
UI->>DS: 写入最新天气数据
Note over UI,Card: 定时更新
FP->>FA: onUpdateForm(formId)
FA->>DS: 读取天气数据
DS-->>FA: 返回数据
FA->>FP: FormBindingData
FP->>Card: 刷新UI
Note over UI,Card: 主动更新
UI->>DS: 写入新数据
UI->>FP: updateForm(formId, data)
FP->>Card: 刷新UI
数据共享方案对比
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| DataShare | 跨进程数据共享 | 标准接口、权限控制 | 开发复杂度高 |
| 分布式KV存储 | 轻量级键值共享 | 简单易用 | 不支持复杂查询 |
| AppStorage | 同进程内共享 | 零延迟 | FormAbility和UIAbility不在同进程 |
| Preferences | 本地持久化 | 简单可靠 | 不支持跨进程 |
AppStorage为什么不行?因为FormAbility和UIAbility虽然可能在同一个应用里,但它们运行在不同的上下文中。AppStorage是进程内的全局状态,FormAbility的上下文和UIAbility的上下文是隔离的。
代码实战
基础用法:DataShare实现UIAbility与FormAbility数据共享
第一步:定义DataShare
// DataShareAbility.ets
import { DataShareExtensionAbility, relationalStore } from '@kit.ArkData'
import { hilog } from '@kit.PerformanceAnalysisKit'
// 数据库配置
const STORE_CONFIG: relationalStore.StoreConfig = {
name: 'card_data.db',
securityLevel: relationalStore.SecurityLevel.S1
}
// 表结构
const CREATE_TABLE_SQL = `
CREATE TABLE IF NOT EXISTS weather_data (
city TEXT PRIMARY KEY,
temperature TEXT,
weather TEXT,
humidity TEXT,
aqi TEXT,
wind TEXT,
update_time INTEGER
)
`
export default class CardDataShare extends DataShareExtensionAbility {
private store: relationalStore.RdbStore | null = null
async onCreate(): void {
hilog.info(0x0000, 'DataShare', 'onCreate')
// 创建数据库
this.store = await relationalStore.getRdbStore(this.context, STORE_CONFIG)
// 创建表
await this.store.executeSql(CREATE_TABLE_SQL)
hilog.info(0x0000, 'DataShare', '数据库初始化完成')
}
// 查询数据
async query(uri: string, columns: string[], predicates: dataSharePredicates.DataSharePredicates): Promise<relationalStore.ResultSet> {
hilog.info(0x0000, 'DataShare', `query: ${uri}`)
if (!this.store) {
throw new Error('数据库未初始化')
}
// 解析URI获取查询条件
const city = this.parseCityFromUri(uri)
const predicates = new relationalStore.RdbPredicates('weather_data')
if (city) {
predicates.equalTo('city', city)
}
return this.store.querySql('SELECT * FROM weather_data WHERE city = ?', [city])
}
// 插入数据
async insert(uri: string, valueBucket: relationalStore.ValuesBucket): Promise<number> {
hilog.info(0x0000, 'DataShare', `insert: ${uri}`)
if (!this.store) {
throw new Error('数据库未初始化')
}
return this.store.insert('weather_data', valueBucket)
}
// 更新数据
async update(uri: string, valueBucket: relationalStore.ValuesBucket, predicates: dataSharePredicates.DataSharePredicates): Promise<number> {
hilog.info(0x0000, 'DataShare', `update: ${uri}`)
if (!this.store) {
throw new Error('数据库未初始化')
}
const city = this.parseCityFromUri(uri)
const rdbPredicates = new relationalStore.RdbPredicates('weather_data')
rdbPredicates.equalTo('city', city)
return this.store.update(valueBucket, rdbPredicates)
}
// 删除数据
async delete(uri: string, predicates: dataSharePredicates.DataSharePredicates): Promise<number> {
hilog.info(0x0000, 'DataShare', `delete: ${uri}`)
if (!this.store) {
throw new Error('数据库未初始化')
}
const city = this.parseCityFromUri(uri)
const rdbPredicates = new relationalStore.RdbPredicates('weather_data')
rdbPredicates.equalTo('city', city)
return this.store.delete(rdbPredicates)
}
private parseCityFromUri(uri: string): string {
// URI格式: datashare:///com.example.weather/card_data/weather/北京
const parts = uri.split('/')
return parts[parts.length - 1] || '北京'
}
}
第二步:在module.json5中声明DataShare
{
"extensionAbilities": [
{
"name": "CardDataShare",
"srcEntry": "./ets/datashare/CardDataShare.ets",
"type": "dataShare",
"uri": "datashare:///com.example.weather/card_data",
"grantPermission": {
"readPermission": "ohos.permission.READ_CARD_DATA",
"writePermission": "ohos.permission.WRITE_CARD_DATA"
}
}
]
}
第三步:UIAbility写入数据
// WeatherUIAbility.ets
import { UIAbility } from '@kit.AbilityKit'
import { dataShare, relationalStore } from '@kit.ArkData'
import { hilog } from '@kit.PerformanceAnalysisKit'
const DATA_SHARE_URI = 'datashare:///com.example.weather/card_data'
export default class WeatherAbility extends UIAbility {
private dataShareHelper: dataShare.DataShareHelper | null = null
async onCreate(): Promise<void> {
// 创建DataShareHelper
this.dataShareHelper = dataShare.createDataShareHelper(this.context, DATA_SHARE_URI)
}
// 写入天气数据
async saveWeatherData(city: string, weather: WeatherInfo): Promise<void> {
if (!this.dataShareHelper) return
const uri = `${DATA_SHARE_URI}/weather/${city}`
const valueBucket: relationalStore.ValuesBucket = {
city: city,
temperature: weather.temperature,
weather: weather.weather,
humidity: weather.humidity,
aqi: weather.aqi,
wind: weather.wind,
update_time: Date.now()
}
try {
// 先尝试更新,失败则插入
const updated = await this.dataShareHelper.update(uri, valueBucket)
if (updated === 0) {
await this.dataShareHelper.insert(uri, valueBucket)
}
hilog.info(0x0000, 'WeatherUI', `天气数据已保存: ${city}`)
// 保存后通知所有卡片更新
this.notifyCardsToUpdate()
} catch (err) {
hilog.error(0x0000, 'WeatherUI', `保存失败: ${err}`)
}
}
// 通知卡片更新
private notifyCardsToUpdate(): void {
// 通过formProvider更新所有活跃卡片
// 具体实现见后面的"卡片联动更新"
}
}
第四步:FormAbility读取数据
// WeatherFormAbility.ets
import { formBindingData, FormExtensionAbility } from '@kit.AbilityKit'
import { dataShare, relationalStore } from '@kit.ArkData'
import { hilog } from '@kit.PerformanceAnalysisKit'
const DATA_SHARE_URI = 'datashare:///com.example.weather/card_data'
export default class WeatherFormAbility extends FormExtensionAbility {
onAddForm(want: Want): formBindingData.FormBindingData {
const city = want.parameters?.['city'] as string || '北京'
// 从DataShare读取数据
const weatherData = this.readWeatherFromDataShare(city)
if (weatherData) {
return formBindingData.createFormBindingData(weatherData)
}
// 读取失败,返回默认数据
return formBindingData.createFormBindingData({
city: city,
temperature: '--°',
weather: '加载中'
})
}
onUpdateForm(formId: string): formBindingData.FormBindingData {
// 更新时也从DataShare读取
const city = this.getCityByFormId(formId)
const weatherData = this.readWeatherFromDataShare(city)
if (weatherData) {
return formBindingData.createFormBindingData(weatherData)
}
return formBindingData.createFormBindingData({
city: city || '--',
temperature: '--°',
weather: '更新失败'
})
}
onRemoveForm(formId: string): void {
hilog.info(0x0000, 'WeatherForm', `卡片删除: ${formId}`)
}
// 从DataShare读取天气数据
private readWeatherFromDataShare(city: string): Record<string, string> | null {
try {
const helper = dataShare.createDataShareHelper(this.context, DATA_SHARE_URI)
if (!helper) return null
const uri = `${DATA_SHARE_URI}/weather/${city}`
const columns = ['city', 'temperature', 'weather', 'humidity', 'aqi', 'wind', 'update_time']
const predicates = new dataShare.DataSharePredicates()
// 同步查询——注意:FormAbility回调中不能做异步操作
// 实际项目中需要用缓存层包装DataShare读取
const resultSet = helper.query(uri, columns, predicates)
if (resultSet && resultSet.goToFirstRow()) {
const data: Record<string, string> = {
city: resultSet.getString(resultSet.getColumnIndex('city')),
temperature: resultSet.getString(resultSet.getColumnIndex('temperature')),
weather: resultSet.getString(resultSet.getColumnIndex('weather')),
humidity: resultSet.getString(resultSet.getColumnIndex('humidity')),
aqi: resultSet.getString(resultSet.getColumnIndex('aqi')),
wind: resultSet.getString(resultSet.getColumnIndex('wind')),
updateTime: this.formatTimestamp(resultSet.getLong(resultSet.getColumnIndex('update_time')))
}
resultSet.close()
return data
}
if (resultSet) resultSet.close()
} catch (err) {
hilog.error(0x0000, 'WeatherForm', `DataShare读取失败: ${err}`)
}
return null
}
private formatTimestamp(ts: number): string {
const date = new Date(ts)
return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
}
private getCityByFormId(formId: string): string {
return '北京'
}
}
进阶用法:多卡片联动更新
当数据变化时,所有使用该数据的卡片都应该同步更新。这就是"联动更新"。
// CardUpdateCoordinator.ets —— 卡片更新协调器
import { formProvider, formBindingData } from '@kit.AbilityKit'
import { hilog } from '@kit.PerformanceAnalysisKit'
// 卡片注册信息
interface CardRegistration {
formId: string
formName: string
dataKeys: string[] // 该卡片依赖的数据key
}
class CardUpdateCoordinator {
private registrations: Map<string, CardRegistration> = new Map()
private static instance: CardUpdateCoordinator
// 数据key到卡片ID的映射
private keyToCards: Map<string, Set<string>> = new Map()
static getInstance(): CardUpdateCoordinator {
if (!CardUpdateCoordinator.instance) {
CardUpdateCoordinator.instance = new CardUpdateCoordinator()
}
return CardUpdateCoordinator.instance
}
// 注册卡片
registerCard(formId: string, formName: string, dataKeys: string[]): void {
this.registrations.set(formId, { formId, formName, dataKeys })
// 建立数据key到卡片的映射
dataKeys.forEach(key => {
if (!this.keyToCards.has(key)) {
this.keyToCards.set(key, new Set())
}
this.keyToCards.get(key)!.add(formId)
})
hilog.info(0x0000, 'Coordinator', `注册卡片: ${formId} (${formName}), 依赖: ${dataKeys.join(',')}`)
}
// 注销卡片
unregisterCard(formId: string): void {
const reg = this.registrations.get(formId)
if (!reg) return
// 清理映射
reg.dataKeys.forEach(key => {
this.keyToCards.get(key)?.delete(formId)
})
this.registrations.delete(formId)
hilog.info(0x0000, 'Coordinator', `注销卡片: ${formId}`)
}
// 数据变化时,联动更新所有相关卡片
async onDataChanged(changedKey: string, newData: Record<string, string>): Promise<void> {
const affectedCards = this.keyToCards.get(changedKey)
if (!affectedCards || affectedCards.size === 0) {
hilog.info(0x0000, 'Coordinator', `无卡片依赖数据: ${changedKey}`)
return
}
hilog.info(0x0000, 'Coordinator', `数据变化: ${changedKey}, 影响 ${affectedCards.size} 张卡片`)
const bindingData = formBindingData.createFormBindingData(newData)
const updatePromises: Promise<void>[] = []
affectedCards.forEach(formId => {
const promise = formProvider.updateForm(formId, bindingData)
.then(() => {
hilog.info(0x0000, 'Coordinator', `卡片更新成功: ${formId}`)
})
.catch((err: Error) => {
hilog.error(0x0000, 'Coordinator', `卡片更新失败: ${formId}, ${err.message}`)
// 卡片可能已删除
if (err.message.includes('not exist')) {
this.unregisterCard(formId)
}
})
updatePromises.push(promise)
})
await Promise.all(updatePromises)
hilog.info(0x0000, 'Coordinator', `联动更新完成: ${changedKey}`)
}
// 批量数据变化
async onBatchDataChanged(changes: Map<string, Record<string, string>>): Promise<void> {
// 收集所有受影响的卡片
const affectedCards = new Set<string>()
changes.forEach((_, key) => {
const cards = this.keyToCards.get(key)
if (cards) {
cards.forEach(formId => affectedCards.add(formId))
}
})
// 对每张受影响的卡片,合并所有相关数据后更新
const updatePromises: Promise<void>[] = []
affectedCards.forEach(formId => {
const reg = this.registrations.get(formId)
if (!reg) return
// 合并该卡片依赖的所有变化数据
let mergedData: Record<string, string> = {}
reg.dataKeys.forEach(key => {
const data = changes.get(key)
if (data) {
mergedData = { ...mergedData, ...data }
}
})
if (Object.keys(mergedData).length === 0) return
const bindingData = formBindingData.createFormBindingData(mergedData)
const promise = formProvider.updateForm(formId, bindingData)
.then(() => {
hilog.info(0x0000, 'Coordinator', `卡片批量更新成功: ${formId}`)
})
.catch((err: Error) => {
hilog.error(0x0000, 'Coordinator', `卡片批量更新失败: ${formId}`)
})
updatePromises.push(promise)
})
await Promise.all(updatePromises)
}
}
const coordinator = CardUpdateCoordinator.getInstance()
export default coordinator
使用方式:
// 在FormAbility中注册
import coordinator from './CardUpdateCoordinator'
onAddForm(want: Want): formBindingData.FormBindingData {
const formId = want.parameters?.['ohos.extra.param.key.form_identity'] as string
const formName = want.parameters?.['ohos.extra.param.key.form_name'] as string
// 注册卡片,声明数据依赖
const dataKeys = this.getDataKeysForCard(formName)
coordinator.registerCard(formId, formName, dataKeys)
return formBindingData.createFormBindingData(this.getInitialData(formName))
}
onRemoveForm(formId: string): void {
coordinator.unregisterCard(formId)
}
// 在UIAbility中触发联动更新
async function onWeatherUpdated(city: string, data: Record<string, string>): Promise<void> {
// 1. 保存到DataShare
await saveToDataShare(city, data)
// 2. 联动更新所有相关卡片
await coordinator.onDataChanged(`weather_${city}`, data)
}
完整示例:待办卡片的数据一致性保障
待办场景对数据一致性要求很高——用户在App里完成一个待办,"今日待办"和"本周待办"两张卡片必须同时更新,不能出现"今日待办显示已完成,本周待办还显示未完成"的情况。
// TodoDataManager.ets —— 待办数据管理器
import { dataShare, relationalStore } from '@kit.ArkData'
import { formProvider, formBindingData } from '@kit.AbilityKit'
import { hilog } from '@kit.PerformanceAnalysisKit'
const DATA_SHARE_URI = 'datashare:///com.example.todo/todo_data'
class TodoDataManager {
private static instance: TodoDataManager
private activeCards: Map<string, { formId: string; formName: string }> = new Map()
private lastUpdateTime: Map<string, number> = new Map()
private readonly MIN_INTERVAL = 5 * 60 * 1000 // 5分钟
static getInstance(): TodoDataManager {
if (!TodoDataManager.instance) {
TodoDataManager.instance = new TodoDataManager()
}
return TodoDataManager.instance
}
// 注册卡片
registerCard(formId: string, formName: string): void {
this.activeCards.set(formId, { formId, formName })
}
// 注销卡片
unregisterCard(formId: string): void {
this.activeCards.delete(formId)
this.lastUpdateTime.delete(formId)
}
// 待办完成——更新所有相关卡片
async onTodoCompleted(todoId: string): Promise<void> {
// 1. 更新数据库
await this.markTodoCompletedInDB(todoId)
// 2. 获取最新的待办统计数据
const todayStats = await this.getTodayStats()
const weekStats = await this.getWeekStats()
// 3. 同时更新所有卡片(确保一致性)
const updateTasks: Promise<void>[] = []
this.activeCards.forEach((info, formId) => {
// 检查更新间隔
const lastUpdate = this.lastUpdateTime.get(formId) || 0
if (Date.now() - lastUpdate < this.MIN_INTERVAL) {
hilog.warn(0x0000, 'TodoData', `更新间隔不足: ${formId}`)
return
}
let data: Record<string, string>
switch (info.formName) {
case 'todayTodoCard':
data = todayStats
break
case 'weekTodoCard':
data = weekStats
break
default:
data = todayStats
}
const bindingData = formBindingData.createFormBindingData(data)
const task = formProvider.updateForm(formId, bindingData)
.then(() => {
this.lastUpdateTime.set(formId, Date.now())
hilog.info(0x0000, 'TodoData', `卡片更新成功: ${formId}`)
})
.catch((err: Error) => {
hilog.error(0x0000, 'TodoData', `更新失败: ${err.message}`)
if (err.message.includes('not exist')) {
this.activeCards.delete(formId)
}
})
updateTasks.push(task)
})
// 等待所有更新完成
await Promise.all(updateTasks)
hilog.info(0x0000, 'TodoData', '所有卡片更新完成')
}
private async markTodoCompletedInDB(todoId: string): Promise<void> {
// 更新数据库
hilog.info(0x0000, 'TodoData', `标记完成: ${todoId}`)
}
private async getTodayStats(): Promise<Record<string, string>> {
return {
totalCount: '5',
completedCount: '2',
latestTodo: '完成周报',
date: new Date().toLocaleDateString()
}
}
private async getWeekStats(): Promise<Record<string, string>> {
return {
totalCount: '25',
completedCount: '10',
completionRate: '40%',
weekRange: '6/23 - 6/29'
}
}
}
const todoManager = TodoDataManager.getInstance()
export default todoManager
踩坑与注意事项
坑1:DataShare查询是同步还是异步?
DataShare的查询操作是异步的,但FormAbility的onUpdateForm回调是同步的。你不能在onUpdateForm里用await等DataShare返回。
解决方案:在FormAbility里维护一个内存缓存层。后台定时从DataShare读取数据到缓存,onUpdateForm直接读缓存。
// 缓存层
let dataCache: Map<string, Record<string, string>> = new Map()
// 后台定时刷新缓存(在FormAbility的onCreate中启动)
setInterval(async () => {
const freshData = await readFromDataShare()
dataCache = freshData
}, 30 * 60 * 1000) // 30分钟刷新一次
// onUpdateForm直接读缓存
onUpdateForm(formId: string): formBindingData.FormBindingData {
const cached = dataCache.get(formId)
if (cached) {
return formBindingData.createFormBindingData(cached)
}
return formBindingData.createFormBindingData({ title: '加载中' })
}
坑2:DataShare权限配置
DataShare需要配置读写权限。如果权限没配好,FormAbility读取数据时会抛异常。
// module.json5
{
"extensionAbilities": [{
"name": "CardDataShare",
"type": "dataShare",
"uri": "datashare:///com.example.weather/card_data",
"grantPermission": {
"readPermission": "ohos.permission.READ_CARD_DATA",
"writePermission": "ohos.permission.WRITE_CARD_DATA"
}
}],
"requestPermissions": [{
"name": "ohos.permission.READ_CARD_DATA"
}, {
"name": "ohos.permission.WRITE_CARD_DATA"
}]
}
坑3:联动更新的5分钟限制
联动更新时,每张卡片都受5分钟间隔限制。如果卡片A刚更新过,数据变化时卡片A不能立即更新,但卡片B可以。这会导致短暂的数据不一致。
解决方案:接受短暂不一致,下次更新时自动修正。或者用动态卡片,不受5分钟限制。
坑4:DataShare URI格式
DataShare的URI格式有严格要求,格式不对会查询失败。
// ✅ 正确格式
const uri = 'datashare:///com.example.weather/card_data/weather/北京'
// ❌ 错误格式
const uri = 'datashare://com.example.weather/card_data/weather/北京' // 少了一个/
const uri = 'content://com.example.weather/card_data/weather/北京' // Android格式
坑5:分布式KV存储的替代方案
如果你的数据很简单(就是几个键值对),用DataShare有点杀鸡用牛刀。分布式KV存储是更轻量的选择:
import { distributedKVStore } from '@kit.ArkData'
// 创建KV存储
const kvManager = distributedKVStore.createKVManager({
bundleName: 'com.example.weather'
})
const kvStore = await kvManager.getKVStore({
storeId: 'card_data',
securityLevel: distributedKVStore.SecurityLevel.S1
})
// 写入
await kvStore.put('weather_beijing', JSON.stringify({ temp: '26°', weather: '晴' }))
// 读取
const value = await kvStore.get('weather_beijing')
const data = JSON.parse(value as string)
KV存储的优势是简单,缺点是不支持复杂查询。如果你的数据有结构化查询需求,还是得用DataShare。
HarmonyOS 6适配说明
-
DataShare性能优化:6.0对DataShare的查询性能做了优化,增加了查询结果缓存。重复查询同一URI时,如果数据没变,直接返回缓存结果,不走数据库。
-
数据变化通知:6.0新增了DataShare的数据变化通知机制。你可以注册一个观察者,当DataShare中的数据变化时,自动收到通知:
// 6.0新增的数据变化观察
const helper = dataShare.createDataShareHelper(context, uri)
helper.on('dataChange', uri, () => {
// 数据变化了,更新卡片
this.updateCardFromDataShare()
})
这个特性极大简化了卡片联动更新的逻辑——不需要手动管理更新协调器了。
- 跨设备数据共享:6.0的DataShare支持跨设备数据共享。用户在手机上更新了待办,平板上的卡片自动同步。你只需要在DataShare配置中启用分布式模式:
{
"extensionAbilities": [{
"type": "dataShare",
"uri": "datashare:///com.example.todo/todo_data",
"distributed": true // 6.0新增,启用跨设备共享
}]
}
- KV存储事务支持:6.0的分布式KV存储新增了事务支持,可以保证多key的原子性更新:
// 6.0新增的事务
kvStore.beginTransaction()
try {
await kvStore.put('today_count', '3')
await kvStore.put('week_count', '15')
kvStore.commit()
} catch (err) {
kvStore.rollback()
}
总结
卡片数据共享是打通UIAbility、FormAbility、多卡片之间数据孤岛的关键。DataShare是标准方案,KV存储是轻量替代。联动更新需要协调器来管理卡片注册和数据分发。
核心要点回顾:
- FormAbility和UIAbility上下文隔离,不能直接共享数据
- DataShare是跨进程数据共享的标准方案
- FormAbility回调是同步的,DataShare查询是异步的,需要缓存层
- 多卡片联动更新需要协调器管理注册和分发
- 5分钟更新限制会导致短暂的数据不一致
- 简单数据用KV存储,复杂查询用DataShare
| 评估维度 | 说明 |
|---|---|
| 学习难度 | ⭐⭐⭐⭐ DataShare配置、缓存层、联动更新都需要深入理解 |
| 使用频率 | ⭐⭐⭐⭐ 大部分卡片都需要数据共享 |
| 重要程度 | ⭐⭐⭐⭐ 没有数据共享,卡片就是信息孤岛 |
下一篇聊卡片性能优化——渲染效率、内存控制、更新频率平衡,让卡片又快又省电。
- 点赞
- 收藏
- 关注作者
评论(0)