作者:井隆

分布式数据对象之功能实践

分布式数据对象管理框架是一款面向对象的内存数据管理框架,向应用开发者提供内存对象的创建、查询、删除、修改、订阅等基本数据对象的管理能力,同时具备分布式能力,满足超级终端场景下,相同应用多设备间的数据对象协同需求。

1 基本概念

分布式数据对象提供JS接口,让开发者能以使用本地对象的方式使用分布式对象。

2 运作示意图

分布式数据对象.png

3 约束与限制

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

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

• 每个对象大小不超过500KB

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

类型名称 类型描述
number 数字
string 字符串
boolean 布尔

4 开发指导

4.1 接口说明

4.1.1 引用分布式对象头文件

import distributedObject from '@ohos.data.distributedDataObject'

4.1.2 接口

接口名称 描述
function createDistributedObject(source: object): DistributedObject; 创建分布式对象 source中指定分布式对象中的属性 返回值是创建出的分布式对象,接口见DistrubutedObject
function genSessionId(): string; 随机创建sessionId 返回值是随机创建的sessionId

4.1.3 DistrubutedObject

接口名称 描述
setSessionId(sessionId?: string): boolean; 设置同步的sessionId,可信组网中有多个设备时,多个设备间的对象如果设置为同一个sessionId,就能自动同步 sessionId是指定的sessionId,如果要退出分布式组网,设置为“”或不设置均可 返回值是操作结果,true标识设置session成功
on(type: 'change', callback: Callback<{ sessionId: string, fields: Array }>): void; 监听对象的变更 type固定为'change' callback是变更时触发的回调,回调参数sessionId标识变更对象的sessionId,fields标识对象变更的属性名
off(type: 'change', callback?: Callback<{ sessionId: string, fields: Array } 删除对象的变更监听 type固定为'change' callback为可选参数,不设置表示删除该对象所有变更监听
on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' | 'offline' }>): void 监听对象的变更 type固定为'status' callback是变更时触发的回调,回调参数sessionId标识变更对象的sessionId,networkId标识对象设备的networkId,status标识对象为'online'(上线)或'offline'(下线)的状态
off(type: 'status', callback?: Callback<{ sessionId: string, deviceId: string, status: 'online' | 'offline' }>): void 删除对象的变更监听 type固定为'change' callback为可选参数,不设置表示删除该对象所有上下线监听

5 开发步骤

5.1 引入接口

import distributedObject from '@ohos.data.distributedDataObject'

5.2 创建对象

// 创建对象,对象包含3个基本属性:name,age和isVis;2个复杂属性:parent,list
var g_object = distributedObject.createDistributedObject({name:undefined, age:undefined, isVis:true, parent:undefined, list:undefined});

说明:构造分布式对象时,新增了默认SESSION_ID属性,并为各属性增加了set和get方法,其构造方法如下所示:

const SESSION_ID = "__sessionId";

class Distributed {
    constructor(obj) {
        this.__proxy = obj;
        Object.keys(obj).forEach(key => {
            Object.defineProperty(this, key, {
                enumerable: true,
                configurable: true,
                get: function () {
                    return this.__proxy[key];
                },
                set: function (newValue) {
                    this.__proxy[key] = newValue;
                }
            });
        });
        Object.defineProperty(this, SESSION_ID, {
            enumerable: true,
            configurable: true,
            get: function () {
                return this.__proxy[SESSION_ID];
            },
            set: function (newValue) {
                this.__proxy[SESSION_ID] = newValue;
            }
        });
        this.__objectId = randomNum();
        console.info("constructor success ");
    }

    //------------------------------------------------------其余内容此处省略

    __proxy;
    __objectId;
}

5.3 加入同步组网

  • 发起方

用distributedObject.genSessionId()方法生成随机字符串,并设置为对象的__sessionId属性的值

g_object.setSessionId(distributedObject.genSessionId());

说明:setSessionId不仅设置了SESSION_ID属性的值,也重新打包了对象,增加了该SESSION_ID对应同步组网的内容,具体方法如下:

setSessionId(sessionId) {
        if (sessionId == null || sessionId == "") {
            leaveSession(this.__proxy);  //退出同步组网
            return false;
        }
        if (this.__proxy[SESSION_ID] == sessionId) {
            console.info("same session has joined " + sessionId);
            return true;
        }
        leaveSession(this.__proxy); //退出同步组网
        //加入sessionId值对应的同步组网,返回新生成的对象
        let object = joinSession(this.__proxy, this.__objectId, sessionId); 
        if (object != null) {
            this.__proxy = object;//替换新生成的对象
            return true;
        }
        return false;
    }
  • 被拉起方

发起方将sessionId通过Intent传到对端设备,被拉起方获取Intent中的sessionId,执行setSessionId加入同步组网完成数据同步。

//sessionId与发起方的__sessionId一致
g_object.setSessionId(sessionId);

5.4 监听对象变更

开启change监听,当同步组网内对象属性value发生变化时,触发用户自定义回调changeCallback。

changeCallback : function (sessionId,  changeData) {
        console.info("change" + sessionId + " " + this.response);

        if (changeData != null && changeData != undefined) {
            changeData.forEach(element => {
                console.info("changed !" + element + " " + g_object[element]);
        });
        }
} 
g_object.on("change", this.changeCallback);

5.5 修改对象属性

g_object.name = "jack";
g_object.age = 19;
g_object.isVis = false; 
g_object.parent = {mother:"jack mom",father:"jack Dad"};
g_object.list = [{mother:"jack mom"}, {father:"jack Dad"}];
// 对端设备收到change回调,fields为name,age,isVis,parent和list

说明: 针对复杂类型的数据修改,目前支持对根属性的修改,暂不支持对下级属性的修改。示例如下:

//支持的修改方式
g_object.parent = {mother:"mom", father:"dad"};
//不支持的修改方式
g_object.parent.mother = "mom";

5.6 访问对象

console.info("name " + g_object["name"]); //访问到的是组网内最新数据

5.7 删除监听数据变更

//删除变更回调changeCallback
g_object.off("change", changeCallback);
//删除所有的变更回调
g_object.off("change"); 

5.8 监听分布式对象的上下线

开启status监听,当同步组网内有对象在线状态发生变化时,触发用户自定义回调statusCallback。

statusCallback : function (sessionId, networkid, status) {
  this.response += "status changed " + sessionId + " " + status + " " + networkId;
}

g_object.on("status", this.changeCallback);

5.9 删除监听分布式对象的上下线

//删除上下线回调changeCallback
g_object.off("status", changeCallback);
//删除所有的上下线回调
g_object.off("status");

5.10 退出同步组网

//两种方式均可
g_object.setSessionId("");
g_object.setSessionId();

6 内部实现

6.1 主要接口

```C++
class DistributedObjectStoreImpl : public DistributedObjectStore
{
public:
DistributedObject CreateObject(const std::string &sessionId) override;
uint32_t DeleteObject(const std::string &sessionId) override;
//此处的watch主要针对change监听
uint32_t Watch(DistributedObject
object, std::shared_ptr<ObjectWatcher> watcher) override;
uint32_t UnWatch(DistributedObject *object) override;

//其余内容省略

}



### 6.2 调用顺序

![主要接口调用顺序.png](https://s4.51cto.com/images/blog/202204/11170645_6253efa53c7af31569.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

## 7 总结

通过本文的学习可了解到分布式数据对象的主要接口、大致调用方法和功能实现等。结合对应内容,可以进一步对分布式数据对象同步机制做深度学习。

下一步,

(1) 着重理解同步组网的构建原理。

(2) 着重理解同步组网内,监听change和status变化的实现。

## 更多原创内容请关注:[深开鸿技术团队](https://harmonyos.51cto.com/person/posts/15292440)

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

[想了解更多关于鸿蒙的内容,请访问:](https://ost.51cto.com/#bkwz)

[51CTO和华为官方合作共建的鸿蒙技术社区](https://ost.51cto.com#bkwz)

https://ost.51cto.com/#bkwz

::: hljs-center

![21_9.jpg](https://s2.51cto.com/images/20210924/1632469265578939.jpg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

:::