HarmonyOS 应用开发之分布式数据对象跨设备数据同步

场景介绍

传统方式下,设备之间的数据同步,需要开发者完成消息处理逻辑,包括:建立通信链接、消息收发处理、错误重试、数据冲突解决等操作,工作量非常大。而且设备越多,调试复杂度也将同步增加。

其实设备之间的状态、消息发送进度、发送的数据等都是“变量”。如果这些变量支持“全局”访问,那么开发者跨设备访问这些变量就能像操作本地变量一样,从而能够自动高效、便捷地实现数据多端同步。

分布式数据对象即实现了对“变量”的“全局”访问。向应用开发者提供内存对象的创建、查询、删除、修改、订阅等基本数据对象的管理能力,同时具备分布式能力。为开发者在分布式应用场景下提供简单易用的JS接口,轻松实现多设备间同应用的数据协同,同时设备间可以监听对象的状态和数据变更。满足超级终端场景下,相同应用多设备间的数据对象协同需求。与传统方式相比,分布式数据对象大大减少了开发者的工作量。

基本概念

  • 分布式内存数据库
    分布式内存数据库将数据缓存在内存中,以便应用获得更快的数据存取速度,不会将数据进行持久化。若数据库关闭,则数据不会保留。

  • 分布式数据对象
    分布式数据对象是一个JS对象型的封装。每一个分布式数据对象实例会创建一个内存数据库中的数据表,每个应用程序创建的内存数据库相互隔离,对分布式数据对象的“读取”或“赋值”会自动映射到对应数据库的get/put操作。

    分布式数据对象的生命周期包括以下状态:

    • 未初始化:未实例化,或已被销毁。
    • 本地数据对象:已创建对应的数据表,但是还无法进行数据同步。
    • 分布式数据对象:已创建对应的数据表,设备在线且组网内设置同样sessionId的对象数>=2,可以跨设备同步数据。若设备掉线或将sessionId置为空,分布式数据对象退化为本地数据对象。

运作机制

图1 分布式数据对象运作机制

分布式数据对象生长在分布式内存数据库之上,在分布式内存数据库上进行了JS对象型的封装,能像操作本地变量一样操作分布式数据对象,数据的跨设备同步由系统自动完成。

JS对象型存储与封装机制

  • 为每个分布式数据对象实例创建一个内存数据库,通过SessionId标识,每个应用程序创建的内存数据库相互隔离。

  • 在分布式数据对象实例化的时候,(递归)遍历对象所有属性,使用“Object.defineProperty”定义所有属性的set和get方法,set和get中分别对应数据库一条记录的put和get操作,Key对应属性名,Value对应属性值。

  • 在开发者对分布式数据对象进行“读取”或者“赋值”的时候,都会自动调用到set和get方法,映射到对应数据库的操作。

表1 分布式数据对象和分布式数据库的对应关系

分布式对象实例对象实例属性名称属性值
分布式内存数据库一个数据库(sessionID标识)一条数据库记录的key一条数据库记录的value

跨设备同步和数据变更通知机制

分布式数据对象,最重要的功能就是对象之间的数据同步。可信组网内的设备可以在本地创建分布式数据对象,并设置sessionID。不同设备上的分布式数据对象,通过设置相同的sessionID,建立对象之间的同步关系。

如下图所示,设备A和设备B上的“分布式数据对象1”,其sessionID均为session1,这两个对象建立了session1的同步关系。

图2 对象的同步关系

一个同步关系中,一个设备只能有一个对象加入。比如上图中,设备A的“分布式数据对象1”已经加入了session1的同步关系,所以设备A的“分布式数据对象2”就加入失败了。

建立同步关系后,每个Session有一份共享对象数据。加入了同一个Session的对象,支持以下操作:

(1)读取/修改Session中的数据。

(2)监听数据变更,感知其他设备对共享对象数据的修改。

(3)监听状态变更,感知其他设备的加入和退出。

同步的最小单位

关于分布式数据对象的数据同步,值得注意的是,同步的最小单位是“属性”。比如,下图中对象1包含三个属性:name、age和parents。当其中一个属性变更时,则数据同步时只需同步此变更的属性。

图3 数据同步视图

对象持久化缓存机制

分布式对象主要运行在应用程序的进程空间。当调用分布式对象持久化接口时,通过分布式数据库对对象进行持久化和同步,进程退出后数据也不会丢失。

该场景是分布式对象的扩展场景,主要用于以下情况:

  • 在设备上创建持久化对象后APP退出,重新打开APP,创建持久化对象,加入同一个Session,数据可以恢复到APP退出前的数据。

  • 在设备A上创建持久化对象并同步后持久化到设备B后,A设备的APP退出,设备B打开APP,创建持久化对象,加入同一个Session,数据可以恢复到A设备退出前的数据。

资产同步机制

在分布式对象中,可以使用资产类型来描述本地实体资产文件,分布式对象跨设备同步时,该文件会和数据一起同步到其他设备上。当前只支持资产类型,不支持资产类型数组。如需同步多个资产,可将每个资产作为分布式对象的一个根属性实现。

融合资产冲突解决机制

当分布式对象中包含的资产和关系型数据库中包含的资产指向同一个实体资产文件,即两个资产的Uri相同时,就会存在冲突,我们把这种资产称为融合资产。若想解决融合资产的冲突,需要先进行资产的绑定。当应用退出session后,绑定关系随之消失。

约束限制

  • 不同设备间只有相同bundleName的应用才能直接同步。

  • 分布式数据对象的数据同步发生在同一个应用程序下,且同sessionID之间。

  • 不建议创建过多的分布式数据对象,每个分布式数据对象将占用100-150KB内存。

  • 每个分布式数据对象大小不超过500KB。

  • 设备A修改1KB数据,设备B收到变更通知,50ms内完成。

  • 单个应用程序最多只能创建16个分布式数据对象实例。

  • 考虑到性能和用户体验,最多不超过3个设备进行数据协同。

  • 如对复杂类型的数据进行修改,仅支持修改根属性,暂不支持下级属性修改。资产同步机制中,资产类型的数据支持下一级属性修改。

  • 支持JS接口间的互通,与其他语言不互通。

接口说明

以下是分布式对象跨设备数据同步功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见分布式数据对象。

接口名称描述
create(context: Context, source: object): DataObject创建并得到一个分布式数据对象实例。
genSessionId(): string创建一个sessionId,可作为分布式数据对象的sessionId。
setSessionId(sessionId: string, callback: AsyncCallback<void>): void设置同步的sessionId,当可信组网中有多个设备时,多个设备间的对象如果设置为同一个sessionId,就能自动同步。
setSessionId(callback: AsyncCallback<void>): void退出所有已加入的session。
on(type: ‘change’, callback: (sessionId: string, fields: Array<string>) => void): void监听分布式数据对象的数据变更。
off(type: ‘change’, callback?: (sessionId: string, fields: Array<string>) => void): void取消监听分布式数据对象的数据变更。
on(type: ‘status’, callback: (sessionId: string, networkId: string, status: ‘online’ | ‘offline’ ) => void): void监听分布式数据对象的上下线。
off(type: ‘status’, callback?: (sessionId: string, networkId: string, status: ‘online’ |‘offline’ ) => void): void取消监听分布式数据对象的上下线。
save(deviceId: string, callback: AsyncCallback<SaveSuccessResponse>): void保存分布式数据对象。
revokeSave(callback: AsyncCallback<RevokeSaveSuccessResponse>): void撤回保存的分布式数据对象。
bindAssetStore(assetKey: string, bindInfo: BindInfo, callback: AsyncCallback<void>): void绑定融合资产。

开发步骤

跨设备数据同步

以一次分布式数据对象同步为例,说明开发步骤。

  1. 导入@ohos.data.distributedDataObject模块。

    import distributedDataObject from '@ohos.data.distributedDataObject';
    
  2. 请求权限。

    1. 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限,配置方式请参见声明权限。
    2. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见向用户申请授权。
  3. 创建并得到一个分布式数据对象实例。

    Stage模型示例:

    // 导入模块
    import distributedDataObject from '@ohos.data.distributedDataObject';
    import UIAbility from '@ohos.app.ability.UIAbility';
    import { BusinessError } from '@ohos.base';
    import window from '@ohos.window';class ParentObject {mother: stringfather: stringconstructor(mother: string, father: string) {this.mother = motherthis.father = father}
    }
    class SourceObject {name: string | undefinedage: number | undefinedisVis: boolean | undefinedparent: Object | undefinedconstructor(name: string | undefined, age: number | undefined, isVis: boolean | undefined, parent: ParentObject | undefined) {this.name = namethis.age = agethis.isVis = isVisthis.parent = parent}
    }class EntryAbility extends UIAbility {onWindowStageCreate(windowStage: window.WindowStage) {let parentSource: ParentObject = new ParentObject('jack mom', 'jack Dad');let source: SourceObject = new SourceObject("jack", 18, false, parentSource);let localObject: distributedDataObject.DataObject = distributedDataObject.create(this.context, source);}
    }
    

    FA模型示例:

    // 导入模块
    import distributedDataObject from '@ohos.data.distributedDataObject';
    import featureAbility from '@ohos.ability.featureAbility';
    // 获取context
    let context = featureAbility.getContext();
    class ParentObject {mother: stringfather: stringconstructor(mother: string, father: string) {this.mother = motherthis.father = father}
    }
    class SourceObject {name: string | undefinedage: number | undefinedisVis: boolean | undefinedparent: ParentObject | undefinedconstructor(name: string | undefined, age: number | undefined, isVis: boolean | undefined, parent: ParentObject | undefined) {this.name = namethis.age = agethis.isVis = isVisthis.parent = parent}
    }
    let parentSource: ParentObject = new ParentObject('jack mom', 'jack Dad');
    let source: SourceObject = new SourceObject("jack", 18, false, parentSource);
    // 创建对象,该对象包含4个属性类型:string、number、boolean和Object
    let localObject: distributedDataObject.DataObject = distributedDataObject.create(context, source);
    
  4. 加入同步组网。同步组网中的数据对象分为发起方和被拉起方。

    // 设备1加入sessionId
    let sessionId: string = '123456';localObject.setSessionId(sessionId);// 和设备1协同的设备2加入同一个session// 创建对象,该对象包含4个属性类型:string、number、boolean和Object
    let remoteSource: SourceObject = new SourceObject(undefined, undefined, undefined, undefined);
    let remoteObject: distributedDataObject.DataObject = distributedDataObject.create(this.context, remoteSource);
    // 收到status上线后remoteObject同步数据,即name变成jack,age变成18
    remoteObject.setSessionId(sessionId);
    
  5. 监听对象数据变更。可监听对端数据的变更,以callback作为变更回调实例。

    localObject.on("change", (sessionId: string, fields: Array<string>) => {console.info("change" + sessionId);if (fields != null && fields != undefined) {for (let index: number = 0; index < fields.length; index++) {console.info(`The element ${localObject[fields[index]]} changed.`);}}
    });
    
  6. 修改对象属性,对象属性支持基本类型(数字类型、布尔类型、字符串类型)以及复杂类型(数组、基本类型嵌套等)。

    localObject["name"] = 'jack1';
    localObject["age"] = 19;
    localObject["isVis"] = false;
    let parentSource1: ParentObject = new ParentObject('jack1 mom', 'jack1 Dad');
    localObject["parent"] = parentSource1;
    

    说明:

    针对复杂类型的数据修改,目前仅支持对根属性的修改,暂不支持对下级属性的修改。

    // 支持的修改方式
    let parentSource1: ParentObject = new ParentObject('mom', 'Dad');
    localObject["parent"] = parentSource1;
    // 不支持的修改方式
    localObject["parent"]["mother"] = 'mom';
    
  7. 访问对象。可以通过直接获取的方式访问到分布式数据对象的属性,且该数据为组网内的最新数据。

    console.info(`name:${localObject['name']}`); 
    
  8. 删除监听数据变更。可以指定删除监听的数据变更回调;也可以不指定,这将会删除该分布式数据对象的所有数据变更回调。

    // 删除变更回调
    localObject.off('change', (sessionId: string, fields: Array<string>) => {console.info("change" + sessionId);if (fields != null && fields != undefined) {for (let index: number = 0; index < fields.length; index++) {console.info("changed !" + fields[index] + " " + localObject[fields[index]]);}}
    });
    // 删除所有的变更回调
    localObject.off('change'); 
    
  9. 监听分布式数据对象的上下线。可以监听对端分布式数据对象的上下线。

    localObject.on('status', (sessionId: string, networkId: string, status: 'online' | 'offline') => {console.info("status changed " + sessionId + " " + status + " " +  networkId);// 业务处理
    });
    
  10. 保存和撤回已保存的数据对象。

    // 保存数据对象,如果应用退出后组网内设备需要恢复对象数据时调用
    localObject.save("local").then((result: distributedDataObject.SaveSuccessResponse) => {console.info(`Succeeded in saving. SessionId:${result.sessionId},version:${result.version},deviceId:${result.deviceId}`);
    }).catch((err: BusinessError) => {console.error(`Failed to save. Code:${err.code},message:${err.message}`);
    });// 撤回保存的数据对象
    localObject.revokeSave().then((result: distributedDataObject.RevokeSaveSuccessResponse) => {console.info(`Succeeded in revokeSaving. Session:${result.sessionId}`);
    }).catch((err: BusinessError) => {console.error(`Failed to revokeSave. Code:${err.code},message:${err.message}`);
    });
    
  11. 删除监听分布式数据对象的上下线。可以指定删除监听的上下线回调;也可以不指定,这将会删除该分布式数据对象的所有上下线回调。

    // 删除上下线回调
    localObject.off('status', (sessionId: string, networkId: string, status: 'online' | 'offline') => {console.info("status changed " + sessionId + " " + status + " " + networkId);// 业务处理
    });
    // 删除所有的上下线回调
    localObject.off('status');
    
  12. 退出同步组网。分布式数据对象退出组网后,本地的数据变更对端不会同步。

    localObject.setSessionId(() => {console.info('leave all session.');
    });
    

跨设备资产同步

分布式对象中加入资产类型属性,可以触发资产同步机制,将资产类型属性所描述的文件同步到其他设备。持有资产文件的设备为发起端,得到资产文件的设备为接收端。

  1. 导入@ohos.data.distributedDataObject@ohos.data.commonType模块。

    import distributedDataObject from '@ohos.data.distributedDataObject';
    import commonType from '@ohos.data.commonType';
    
  2. 请求权限。

    1. 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限。
    2. 同时需要在应用首次启动时弹窗向用户申请授权。
  3. 发起端创建包含资产的分布式对象并加入组网。

    import UIAbility from '@ohos.app.ability.UIAbility';
    import type window from '@ohos.window';
    import distributedDataObject from '@ohos.data.distributedDataObject';
    import commonType from '@ohos.data.commonType';
    import type { BusinessError } from '@ohos.base';class Note {title: string | undefinedtext: string | undefinedattachment: commonType.Asset | undefinedconstructor(title: string | undefined, text: string | undefined, attachment: commonType.Asset | undefined) {this.title = title;this.text = text;this.attachment = attachment;}
    }class EntryAbility extends UIAbility {onWindowStageCreate(windowStage: window.WindowStage) {let attachment: commonType.Asset = {name: 'test_img.jpg',uri: 'file://com.example.myapplication/data/storage/el2/distributedfiles/dir/test_img.jpg',path: '/dir/test_img.jpg',createTime: '2024-01-02 10:00:00',modifyTime: '2024-01-02 10:00:00',size: '5',status: commonType.AssetStatus.ASSET_NORMAL}// 创建一个自定义笔记类型,其中包含一张图片资产let note: Note = new Note('test', "test", attachment);let localObject: distributedDataObject.DataObject = distributedDataObject.create(this.context, note);localObject.setSessionId('123456');}
    }
    
  4. 接收端创建分布式对象并加入组网

    let note: Note = new Note(undefined, undefined, undefined);
    let receiverObject: distributedDataObject.DataObject = distributedDataObject.create(this.context, note);
    receiverObject.on('change', (sessionId: string, fields: Array<string>) => {if (fields.includes('attachment')) {// 接收端监听到资产类型属性的数据变更时,代表其所描述的资产文件同步完成console.info('attachment synchronization completed');}
    });
    receiverObject.setSessionId('123456');
    
  5. 若资产为融合资产,可以创建绑定信息,绑定融合资产,以解决融合资产的冲突。

    const bindInfo: distributedDataObject.BindInfo = {storeName: 'notepad',tableName: 'note_t',primaryKey: {'uuid': '00000000-0000-0000-0000-000000000000'},field: 'attachment',assetName: attachment.name
    }localObject.bindAssetStore('attachment', bindInfo, (err: BusinessError) => {if (err) {console.error('bindAssetStore failed.');}console.info('bindAssetStore success.');
    });
    

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/586333.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s集群pod和node状态监控

1.安装 kube-state-metrics 1.1下载yaml文件 下载的文件统一放到目录 &#xff1a; /opt curl -L -O https://raw.githubusercontent.com/gjeanmart/kauri-content/master/spring-boot-simple/k8s/kube-state-metrics.yml 1.2修改配置文件 修改namespace为dev&#xff08;def…

nvm控制node修改版本 - 详细版

随着前端项目的越来越多&#xff0c;不同项目使用的nodejs版本可能不一样&#xff0c;导致在切换不同项目时需要更换不同的nodejs版本&#xff0c;非常麻烦。本次推荐使用nvm进行多个nodejs版本的统一管理 1. nvm即Node版本管理器&#xff0c; 本文已windows版本为例。 a.如果…

2024年【危险化学品经营单位安全管理人员】试题及解析及危险化学品经营单位安全管理人员操作证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品经营单位安全管理人员试题及解析是安全生产模拟考试一点通总题库中生成的一套危险化学品经营单位安全管理人员操作证考试&#xff0c;安全生产模拟考试一点通上危险化学品经营单位安全管理人员作业手机同步…

打造安全医疗网络:三网整体规划与云数据中心构建策略

医院网络安全问题涉及到医院日常管理多个方面&#xff0c;一旦医院信息管理系统在正常运行过程中受到外部恶意攻击&#xff0c;或者出现意外中断等情况&#xff0c;都会造成海量医疗数据信息的丢失。由于医院信息管理系统中存储了大量患者个人信息和治疗方案信息等&#xff0c;…

无问芯穹 MaaS AI 平台公测免费试用笔记:二

上一篇笔记中&#xff0c;聊过了无问芯穹的 MaaS 服务中的“虚拟机”产品。本篇文章来聊聊最近宣传中提到的大手笔免费百亿 Token 用量的“大模型服务平台” 吧。 分享下这个支持异构芯片推理的国产 “Replicate”、模型市场服务使用的经验和小技巧。 写在前面 本篇文章根据…

基于GEC6818的智能火锅点餐系统

本次项目开发环境&#xff1a;gec6818&#xff0c;QT5.14.2&#xff0c;SecureCRT。 所使用的相关技术&#xff1a;c/s架构&#xff0c;STL库&#xff0c;C封装&#xff0c;标准化代码编写 实现的功能&#xff1a;用户登录页面&#xff0c;食品分区在不同页面&#xff0c;用户…

python mysql 查询字典类型

python mysql 查询字典类型 常见的类型&#xff0c;本次使用DictCursor 具体代码 Author: Jeff.zheng Date : 2024-04-02 Desc : 修改游标 import pymysqlif __name__ __main__:connection connection pymysql.connect(host"192.168.10.163", user"root&…

【Redis 知识储备】应⽤数据分离架构 -- 分布系统的演进(2)

应⽤数据分离架构 随着系统的上线&#xff0c;我们不出意外地获得了成功。市场上出现了⼀批忠实于我们的⽤⼾&#xff0c;使得系统的访问量逐步上升&#xff0c;逐渐逼近了硬件资源的极限&#xff0c;同时团队也在此期间积累了对业务流程的⼀批经验。⾯对当前的性能压⼒&#x…

马上蓝桥了,干货总结基础树论知识点

目录 今日知识点&#xff1a;对于每个子树如果和小于0就返回0&#xff1b;如果大于0就直接返回。 注意异或的性质&#xff0c;偶消奇不消&#xff0c;所以lca上面的都消掉了&#xff0c;并不需要跑lca&#xff0c;也就是说只需要把根到所有点的距离跑出来即可 如果上传过来小…

基于 YOLO V8 Pose Fine-Tuning 训练 15 点人脸关键点检测模型

一、YOLO V8 Pose YOLO V8 在上篇文章中进了简单的介绍&#xff0c;并基于YOLO V8 Fine-Tuning 训练了自定义的目标检测模型&#xff0c;而YOLO V8 Pose 是建立在YOLO V8基础上的关键点检测模型&#xff0c;本文基于 yolov8n-pose 模型实验 Fine-Tuning 训练15 点人脸关键点检…

我的C++奇迹之旅:值和引用的本质效率与性能比较

文章目录 &#x1f4dd;引用&#x1f320;引用概念&#x1f309;引用特性 &#x1f320;使用场景&#x1f309;做参数&#xff08;传值与传地址&#xff09;&#x1f309;传值、传引用效率比较 &#x1f320;引用做返回值&#x1f309;引用和指针的区别 &#x1f320;常引用&am…

Visual Studio安装遇到的问题

因为在安装pytorch3d0.3.0时遇到问题&#xff0c;提示没有cl.exe&#xff0c;VS的C编译组件&#xff0c;查了下2019版比2022问题少&#xff0c;下载安装时遇到的问题记录&#xff1a; 查看搜素栏搜时间&#xff0c;查看系统日志&#xff0c;报错为&#xff1a; 创建 TLS 客户端…