HarmonyOS 应用开发之同应用跨设备数据同步

314 篇文章 8 订阅
249 篇文章 7 订阅

概述

场景介绍

跨设备数据同步功能(即分布式功能),指将数据同步到一个组网环境中的其他设备。常用于用户应用程序数据内容在可信认证的不同设备间,进行自由同步、修改和查询。

例如:当设备1上的应用A在分布式数据库中增、删、改数据后,设备2上的应用A也可以获取到该数据库变化。可在分布式图库、备忘录、联系人、文件管理器等场景中使用。

根据跨设备同步数据生命周期的不同,可以分为:

  • 临时数据生命周期较短,通常保存到内存中。比如游戏应用产生的过程数据,建议使用分布式数据对象。

  • 持久数据生命周期较长,需要保存到存储的数据库中,根据数据关系和特点,可以选择关系型数据库或者键值型数据库。比如图库应用的各种相册、封面、图片等属性信息,建议使用关系型数据库;图库应用的具体图片缩略图,建议使用键值型数据库。

基本概念

在分布式场景中,会涉及多个设备,组网内设备之间看到的数据是否一致称为分布式数据库的一致性。

分布式数据库一致性可以分为强一致性、弱一致性和最终一致性。

  • 强一致性:是指某一设备成功增、删、改数据后,组网内设备对该数据的读取操作都将得到更新后的值。对于已改变写的数据的读取,最终都能取得已更新的数据,但不完全保证能立即取得已更新的数据。

  • 弱一致性:是指某一设备成功增、删、改数据后,组网内设备可能读取到本次更新后的数据,也可能读取不到,不能保证在多长时间后每个设备的数据一定是一致的。

  • 最终一致性:是指某一设备成功增、删、改数据后,组网内设备可能读取不到本次更新后的数据,但在某个时间窗口之后组网内设备的数据能够达到一致状态。

强一致性对分布式数据的管理要求非常高,在服务器的分布式场景可能会遇到。因为移动终端设备的不常在线、以及无中心的特性,所以同应用跨设备数据同步不支持强一致性,只支持最终一致性。

跨设备同步访问控制机制

数据跨设备同步时,数据管理基于设备等级和数据安全标签进行访问控制。

键值型数据库跨设备数据同步

场景介绍

键值型数据库适合不涉及过多数据关系和业务关系的业务数据存储,比SQL数据库存储拥有更好的读写性能,同时因其在分布式场景中降低了解决数据库版本兼容问题的复杂度,和数据同步过程中冲突解决的复杂度而被广泛使用。

基本概念

在使用键值型数据库跨设备数据同步前,请先了解以下概念。

单版本数据库

单版本是指数据在本地是以单个条目为单位的方式保存,当数据在本地被用户修改时,不管它是否已经被同步出去,均直接在这个条目上进行修改。多个设备全局只保留一份数据,多个设备的相同记录(主码相同)会按时间最新保留一条记录,数据不分设备,设备之间修改相同的key会覆盖。同步也以此为基础,按照它在本地被写入或更改的顺序将当前最新一次修改逐条同步至远端设备,常用于联系人、天气等应用存储场景。

多设备协同数据库

多设备协同分布式数据库建立在单版本数据库之上,对应用程序存入的键值型数据中的Key前面拼接了本设备的DeviceID标识符,这样能保证每个设备产生的数据严格隔离。数据以设备的维度管理,不存在冲突;支持按照设备的维度查询数据。

底层按照设备的维度管理这些数据,多设备协同数据库支持以设备的维度查询分布式数据,但是不支持修改远端设备同步过来的数据。需要分开查询各设备数据的可以使用设备协同版本数据库。常用于图库缩略图存储场景。

同步方式

数据管理服务提供了两种同步方式:手动同步和自动同步。键值型数据库可选择其中一种方式实现同应用跨设备数据同步。

  • 手动同步:由应用程序调用sync接口来触发,需要指定同步的设备列表和同步模式。同步模式分为PULL_ONLY(将远端数据拉取到本端)、PUSH_ONLY(将本端数据推送到远端)和PUSH_PULL(将本端数据推送到远端同时也将远端数据拉取到本端)。 带有Query参数的同步接口 ,支持按条件过滤的方法进行同步,将符合条件的数据同步到远端。

  • 自动同步:由分布式数据库自动将本端数据推送到远端,同时也将远端数据拉取到本端来完成数据同步,同步时机包括设备上线、应用程序更新数据等,应用不需要主动调用sync接口。

运作机制

底层通信组件完成设备发现和认证,会通知上层应用程序设备上线。收到设备上线的消息后数据管理服务可以在两个设备之间建立加密的数据传输通道,利用该通道在两个设备之间进行数据同步。

数据跨设备同步机制

如图所示,通过put、delete接口触发自动同步,将分布式数据通过通信适配层发送给对端设备,实现分布式数据的自动同步;

手动同步则是手动调用sync接口触发同步,将分布式数据通过通信适配层发送给对端设备。

数据变化通知机制

增、删、改数据库时,会给订阅者发送数据变化的通知。主要分为本地数据变化通知和分布式数据变化通知。

  • 本地数据变化通知:本地设备的应用内订阅数据变化通知,数据库增删改数据时,会收到通知。

  • 分布式数据变化通知:同一应用订阅组网内其他设备数据变化的通知,其他设备增删改数据时,本设备会收到通知。

约束限制

  • 设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度<4 MB。

  • 单版本数据库,针对每条记录,Key的长度≤1 KB,Value的长度<4 MB。

  • 键值型数据库不支持应用程序自定义冲突解决策略。

  • 每个应用程序最多支持同时打开16个键值型分布式数据库。

  • 单个数据库最多支持注册8个订阅数据变化的回调。

接口说明

以下是单版本键值型分布式数据库跨设备数据同步功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例。

接口名称描述
createKVManager(config: KVManagerConfig): KVManager创建一个KVManager对象实例,用于管理数据库对象。
getKVStore<T>(storeId: string, options: Options, callback: AsyncCallback<T>): void指定Options和storeId,创建并得到指定类型的KVStore数据库。
put(key: string, value: Uint8Array|string|number|boolean, callback: AsyncCallback<void>): void插入和更新数据。
on(event: ‘dataChange’, type: SubscribeType, listener: Callback<ChangeNotification>): void订阅数据库中数据的变化。
get(key: string, callback: AsyncCallback<boolean | string | number | Uint8Array>): void查询指定Key键的值。
sync(deviceIds: string[], mode: SyncMode, delayMs?: number): void在手动模式下,触发数据库同步。

开发步骤

此处以单版本键值型数据库跨设备数据同步的开发为例。以下是具体的开发流程和开发步骤。

说明:
数据只允许向数据安全标签不高于对端设备安全等级的设备同步数据,具体规则可见 跨设备同步访问控制机制 。

  1. 导入模块。
   import distributedKVStore from '@ohos.data.distributedKVStore';
  1. 请求权限。

    1. 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限。
    2. 同时需要在应用首次启动时弹窗向用户申请授权。
  2. 根据配置构造分布式数据库管理类实例。

    1. 根据应用上下文创建kvManagerConfig对象。
    2. 创建分布式数据库管理器实例。
   // Stage模型获取context
   import window from '@ohos.window';
   import UIAbility from '@ohos.app.ability.UIAbility';
   import { BusinessError } from '@ohos.base';
   
   let kvManager: distributedKVStore.KVManager | undefined = undefined;
   
   class EntryAbility extends UIAbility {
     onWindowStageCreate(windowStage:window.WindowStage) {
       let context = this.context;
     }
   }
    
    // FA模型获取context
   import featureAbility from '@ohos.ability.featureAbility';
   import { BusinessError } from '@ohos.base';
    
   let context = featureAbility.getContext();
   
   // 获取context之后,构造分布式数据库管理类实例
   try {
     const kvManagerConfig: distributedKVStore.KVManagerConfig = {
       bundleName: 'com.example.datamanagertest',
       context: context
     }
     kvManager = distributedKVStore.createKVManager(kvManagerConfig);
     console.info('Succeeded in creating KVManager.');
     // 继续创建获取数据库
   } catch (e) {
     let error = e as BusinessError;
     console.error(`Failed to create KVManager. Code:${error.code},message:${error.message}`);
   }
   
   if (kvManager !== undefined) {
     kvManager = kvManager as distributedKVStore.KVManager;
     // 进行后续创建数据库等相关操作
     // ...
   }
  1. 获取并得到指定类型的键值型数据库。

    1. 声明需要创建的分布式数据库ID描述(例如示例代码中的’storeId’)。
    2. 创建分布式数据库,建议关闭自动同步功能(autoSync:false),方便后续对同步功能进行验证,需要同步时主动调用sync接口。
   let kvStore: distributedKVStore.SingleKVStore | undefined = undefined;
   try {
     const options: distributedKVStore.Options = {
       createIfMissing: true,
       encrypt: false,
       backup: false,
       autoSync: false,
       // kvStoreType不填时,默认创建多设备协同数据库
       kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
       // 多设备协同数据库:kvStoreType: distributedKVStore.KVStoreType.DEVICE_COLLABORATION,
       securityLevel: distributedKVStore.SecurityLevel.S1
     };
     kvManager.getKVStore<distributedKVStore.SingleKVStore>('storeId', options, (err, store: distributedKVStore.SingleKVStore) => {
       if (err) {
         console.error(`Failed to get KVStore: Code:${err.code},message:${err.message}`);
         return;
       }
       console.info('Succeeded in getting KVStore.');
       kvStore = store;
       // 请确保获取到键值数据库实例后,再进行相关数据操作
     });
   } catch (e) {
     let error = e as BusinessError;
     console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
   }
   if (kvStore !== undefined) {
     kvStore = kvStore as distributedKVStore.SingleKVStore;
       // 进行后续相关数据操作,包括数据的增、删、改、查、订阅数据变化等操作
       // ...
   }
  1. 订阅分布式数据变化,如需关闭订阅分布式数据变化,调用 off(‘dataChange’) 关闭。
   try {
     kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, (data) => {
       console.info(`dataChange callback call data: ${data}`);
     });
   } catch (e) {
     let error = e as BusinessError;
     console.error(`An unexpected error occurred. code:${error.code},message:${error.message}`);
   }
  1. 将数据写入分布式数据库。

    1. 构造需要写入分布式数据库的Key(键)和Value(值)。
    2. 将键值数据写入分布式数据库。
   const KEY_TEST_STRING_ELEMENT = 'key_test_string';
   const VALUE_TEST_STRING_ELEMENT = 'value_test_string';
   try {
     kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => {
       if (err !== undefined) {
         console.error(`Failed to put data. Code:${err.code},message:${err.message}`);
         return;
       }
       console.info('Succeeded in putting data.');
     });
   } catch (e) {
     let error = e as BusinessError;
     console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
   }
  1. 查询分布式数据库数据。

    1. 构造需要从单版本分布式数据库中查询的Key(键)。
    2. 从单版本分布式数据库中获取数据。
   const KEY_TEST_STRING_ELEMENT = 'key_test_string';
   const VALUE_TEST_STRING_ELEMENT = 'value_test_string';
   try {
     kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => {
       if (err !== undefined) {
         console.error(`Failed to put data. Code:${err.code},message:${err.message}`);
         return;
       }
       console.info('Succeeded in putting data.');
       kvStore = kvStore as distributedKVStore.SingleKVStore;
       kvStore.get(KEY_TEST_STRING_ELEMENT, (err, data) => {
         if (err != undefined) {
           console.error(`Failed to get data. Code:${err.code},message:${err.message}`);
           return;
         }
         console.info(`Succeeded in getting data. Data:${data}`);
       });
     });
   } catch (e) {
     let error = e as BusinessError;
     console.error(`Failed to get data. Code:${error.code},message:${error.message}`);
   }
  1. 同步数据到其他设备。

选择同一组网环境下的设备以及同步模式(需用户在应用首次启动的弹窗中确认选择同步模式),进行数据同步。

说明:
在手动同步的方式下,其中的deviceIds通过调用 devManager.getAvailableDeviceListSync 方法得到。

   import deviceManager from '@ohos.distributedDeviceManager';
    
   let devManager: deviceManager.DeviceManager;
   try {
     // create deviceManager
     devManager = deviceManager.createDeviceManager(context.applicationInfo.name);
     // deviceIds由deviceManager调用getAvailableDeviceListSync方法得到
     let deviceIds: string[] = [];
     if (devManager != null) {
       let devices = devManager.getAvailableDeviceListSync();
       for (let i = 0; i < devices.length; i++) {
         deviceIds[i] = devices[i].networkId as string;
       }
     }
     try {
       // 1000表示最大延迟时间为1000ms
       kvStore.sync(deviceIds, distributedKVStore.SyncMode.PUSH_ONLY, 1000);
     } catch (e) {
       let error = e as BusinessError;
       console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
     }
   
   } catch (err) {
     let error = err as BusinessError;
     console.error("createDeviceManager errCode:" + error.code + ",errMessage:" + error.message);
   }

为了能让大家更好的学习鸿蒙(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.鸿蒙南向开发方向

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值