OpenHarmony3.1 分布式应用开发之分布式任务调度

主要包含启动远程设备的FA连接远程设备的Service

startLocalFA.png connectRemoteService.png

HarmonyOS与openHarmony有2个重要的不同(坑点) 在本页面搜索“坑点”,即可快速知道

一)启动远程设备的FA

FA可以简单认为是页面

应用场景:设备A启动设备B的相册

1.设置签名:

为了能让dayu200开发板顺利运行应用,需要设置前面

File->Project Structure->Project->Signing configs->勾选Automatically generate signing->Apply->OK

2.创建另一个Ability

右键entry模块->New->Ability->PageAbility

3.启动本地的FA

featureAbility.startAbility({//需要导入 import featureAbility from "@ohos.ability.featureAbility"
    want://跨设备启动,需要哪些参数?设备Id,app,页面名字
    {
        deviceId: "",//指定设备Id  本地设备Id默认空字符串
        bundleName: "com.example.myohtest",//指定App看  config.json app->bundleName
        abilityName: "com.example.entry.SecondAbility"//指定页面名  坑点,与HarmonyOS不同  openHarmony的这里为 config.json中的package参数+页面名
    }
})

4.启动远程设备的FA

一个设备启动另一个设备的FA,首先需要在config.json中配置权限

1)非敏感权限配置在reqPermissions中,敏感权限还需要运行弹窗的方式用户授权,需要代码进行

"reqPermissions":[ //非敏感权限
{
	"name":"ohos.permission.DISTRIBUTED_DATASYNC"//分布式数据同步的权限  
}
]

2)敏感权限通过弹窗配置

aboutToAppear(){
	requestPermission();
}

通过运行时,用户弹窗的方式,请求用户授权

在start_remote_fa.ets头部加上requestPermission方法

import bundle from '@ohos.bundle';
import abilityAccessCtrl from "@ohos.abilityAccessCtrl";

async function requestPermission() {//可直接复用,2个地方需要修改一下  下一行的授权与下2行的包名
    let array: Array<string> = ["ohos.permission.DISTRIBUTED_DATASYNC"];//这部分需要修改,改成对应的授权
    const appInfo = await bundle.getApplicationInfo('com.example.myohtest', 0, 100);//一参:包名, 二参:bundle的标记 ,三参:user的id
    let tokenID = appInfo.accessTokenId;	//令牌Id相当于安全标识
    const atManager = abilityAccessCtrl.createAtManager();
    let requestPermissions: Array<string> = [];	//用于存放用户未授权的权限
	//遍历每一个权限,判断权限是否已经通过用户授权
    for (let i = 0; i < array.length; i++) {
        let result = await atManager.verifyAccessToken(tokenID, array[i]);	//通过tokenId判断是否有访问的权限
        if (result != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {	//如果未授予该权限,则放入用户需要请求的权限列表中
            requestPermissions.push(array[i]);
        }
    }
	//没有需要授权的权限
    if (requestPermissions.length == 0 || requestPermissions == []) {
        return;
    }
    let context = featureAbility.getContext();
    context.requestPermissionsFromUser(requestPermissions, 1, (data)=>{
        console.info("xxxxxx data:" + JSON.stringify(data));
		//        console.info("data requestCode:" + data.requestCode);
        //        console.info("data permissions:" + data.permissions);
        //        console.info("data authResults:" + data.authResults);
    });
}

3)FeatureAblity的DevideId如何获取?

import deviceManager from '@ohos.distributedHardware.deviceManager';
								
                                                    //参数1 bundleName,参数2 回调函数
        deviceManager.createDeviceManager("com.example.myohtest", (err, value) => {
            if (!err) {
                let devManager = value;
                let deviceList = devManager.getTrustedDeviceListSync();//以同步的方式获得已信任的设备列表


                //把start_local_fa.ets调用本地页面的代码拷过来
                featureAbility.startAbility({
                    want:
                    {
                        deviceId: deviceList[0].deviceId,//组网环境下只有2台设备时,那么当前设备的已信任列表只有一个设备,直接用即可
                        //若有多个设备,则需要弹出对话框,列出所有设备,通过单选按钮,选择想要的目标设备										
                        bundleName: "com.example.myohtest",
                        abilityName: "com.example.entry.SecondAbility"
                    }
                }).then((data) => {
                    console.info('xxxxxxOperation successful. Data: ' + JSON.stringify(data))
                }).catch((error) => {
                    console.error('xxxxxxOperation failed. Cause: ' + JSON.stringify(error));
                })
            }
        });

4) 修改config.json

“js”目录下 name为".MainAbility"的"pages"修改为"pages/start_remote_fa"

5)完整代码

a.start_local_fa.ets
import featureAbility from '@ohos.ability.featureAbility'

@Entry
@Component
struct Index {
    @State message: string = 'Main'

    build() {
        Row() {
            Column() {
                Text(this.message)
                    .fontSize(50)
                    .fontWeight(FontWeight.Bold)
                Button('启动本地设备的Second')
                    .width(500)
                    .height(80)
                    .fontSize(50)
                    .align(Alignment.Center)
                    .backgroundColor('#AD9D8F')
                    .fontColor('#FFFFFF')
                    .borderRadius(10)
                    .margin(1)
                    .onClick((event: ClickEvent) => {
                        featureAbility.startAbility({
                            want:
                            {
                                deviceId: "",
                                bundleName: "com.example.myohtest",
                                abilityName: "com.example.entry.SecondAbility"
                            }
                        })
                    });
            }
            .width('100%')
        }
        .height('100%')
    }
}





b.start_remote_fa.ets

import featureAbility from '@ohos.ability.featureAbility'
import bundle from '@ohos.bundle';
import abilityAccessCtrl from "@ohos.abilityAccessCtrl";
import deviceManager from '@ohos.distributedHardware.deviceManager';

async function requestPermission() {//可直接复用,2个地方需要修改一下  下一行的授权与下2行的包名
    let array: Array<string> = ["ohos.permission.DISTRIBUTED_DATASYNC"];//这部分需要修改,改成对应的授权
    const appInfo = await bundle.getApplicationInfo('com.example.myohtest', 0, 100);//一参:包名, 二参:bundle的标记 ,三参:user的id
    let tokenID = appInfo.accessTokenId;	//令牌Id相当于安全标识
    const atManager = abilityAccessCtrl.createAtManager();
    let requestPermissions: Array<string> = [];	//用于存放用户未授权的权限
	//遍历每一个权限,判断权限是否已经通过用户授权
    for (let i = 0; i < array.length; i++) {
        let result = await atManager.verifyAccessToken(tokenID, array[i]);	//通过tokenId判断是否有访问的权限
        if (result != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {	//如果未授予该权限,则放入用户需要请求的权限列表中
            requestPermissions.push(array[i]);
        }
    }
	//没有需要授权的权限
    if (requestPermissions.length == 0 || requestPermissions == []) {
        return;
    }
    let context = featureAbility.getContext();
    context.requestPermissionsFromUser(requestPermissions, 1, (data)=>{
        console.info("xxxxxx data:" + JSON.stringify(data));
		//        console.info("data requestCode:" + data.requestCode);
        //        console.info("data permissions:" + data.permissions);
        //        console.info("data authResults:" + data.authResults);
    });
}

@Entry
@Component
struct Index {
    @State message: string = 'Main'

    aboutToAppear(): void  {
        requestPermission();
    }

    build() {
        Row() {
            Column() {
                Text(this.message)
                    .fontSize(50)
                    .fontWeight(FontWeight.Bold)
                Button('启动远程设备的Second')
                    .width(500)
                    .height(80)
                    .fontSize(50)
                    .align(Alignment.Center)
                    .backgroundColor('#AD9D8F')
                    .fontColor('#FFFFFF')
                    .borderRadius(10)
                    .margin(1)
                    .onClick((event: ClickEvent) => {//参数1 bundleName,参数2 回调函数
                        deviceManager.createDeviceManager("com.example.myohtest", (err, value) => {
                            if (!err) {
                                let devManager = value;
                                let deviceList = devManager.getTrustedDeviceListSync();//以同步的方式获得已信任的设备列表
								
								
								//把start_local_fa.ets调用本地页面的代码拷过来
                                featureAbility.startAbility({
                                    want:
                                    {
                                        deviceId: deviceList[0].deviceId,//组网环境下只有2台设备时,那么当前设备的已信任列表只有一个设备,直接用即可
										//若有多个设备,则需要弹出对话框,列出所有设备,通过单选按钮,选择想要的目标设备										
                                        bundleName: "com.example.myohtest",
                                        abilityName: "com.example.entry.SecondAbility"
                                    }
                                }).then((data) => {
                                    console.info('xxxxxxOperation successful. Data: ' + JSON.stringify(data))
                                }).catch((error) => {
                                    console.error('xxxxxxOperation failed. Cause: ' + JSON.stringify(error));
                                })
                            }
                        });
                    })
            }
            .width('100%')
        }
        .height('100%')
    }
}

二)连接远程的Service

参考链接

1.连接本地的Service

Service:后台服务

1)connect_local_service.ets

featureAbility.connectAbility(
    {//参数1与启动本地的FA一致
        deviceId: "",
        bundleName: "com.example.myohtest",
        abilityName: "com.example.entry.ServiceAbility",
    },
    {//参数2为3个回调函数
        onConnect: onConnectCallback,
        onDisconnect: onDisconnectCallback,
        onFailed: onFailedCallback
    },
);

2)在该文件首部定义三个回调方法

import prompt from '@system.prompt';
import rpc from "@ohos.rpc";

function onConnectCallback(element, remote){
    console.info('xxxxxx onConnectCallback element: ' + element);
    console.info('xxxxxx onConnectCallback remote: ' + remote);
    if (remote == null) {
        prompt.showToast({
            message: "onConnectLocalService not connected yet"
        });
        return;
    }
    let option = new rpc.MessageOption();
    let data = new rpc.MessageParcel();
    let reply = new rpc.MessageParcel();
    data.writeInt(3);//写入数据
    data.writeInt(5);
    remote.sendRequest(1, data, reply, option).then((result) => {
        console.info('xxxxxx sendRequest success');
        let msg = reply.readInt();
        prompt.showToast({
            message: "onConnectLocalService connect result: " + msg,
            duration: 3000 //显示时间3s
        });
    }).catch((e) => {
        console.info('xxxxxx sendRequest error:' + e);
    });
}

function onDisconnectCallback(element){
    console.info('xxxxxx onDisconnectCallback')
}

function onFailedCallback(code){
    console.info('xxxxxx onDisconnectCallback')
}

3) 创建ServiceAbility

右键Entry->New->Ability->ServiceAbility

import rpc from "@ohos.rpc";

class FirstServiceAbilityStub extends rpc.RemoteObject{
    constructor(des) {
        if (typeof des === 'string') {
            super(des);
        } else {
            return null;
        }
    }
    onRemoteRequest(code, data, reply, option) {
        console.info("xxxxxx ServiceAbility onRemoteRequest called");
        if (code === 1) {//约定好的暗号
            let op1 = data.readInt();//读取数据
            let op2 = data.readInt();
            console.info("xxxxxx op1 = " + op1 + ", op2 = " + op2);
            reply.writeInt(op1 + op2);//写入数据到reply
        } else {
            console.info("xxxxxx ServiceAbility unknown request code");
        }
        return true;
    }
}

export default {
    onConnect(want) {
        console.info("xxxxxx ServiceAbility onConnect");
        try {
            let value = JSON.stringify(want);
            console.info("xxxxxx ServiceAbility want:" + value);
        } catch(error) {
            console.info("xxxxxx ServiceAbility error:" + error);
        }
        return new FirstServiceAbilityStub("first ts service stub");//返回桩类
    }
};

4)完整代码

import featureAbility from '@ohos.ability.featureAbility'
import prompt from '@system.prompt';
import rpc from "@ohos.rpc";

function onConnectCallback(element, remote){
    console.info('xxxxxx onConnectCallback element: ' + element);
    console.info('xxxxxx onConnectCallback remote: ' + remote);
    if (remote == null) {
        prompt.showToast({
            message: "onConnectLocalService not connected yet"
        });
        return;
    }
    let option = new rpc.MessageOption();
    let data = new rpc.MessageParcel();
    let reply = new rpc.MessageParcel();
    data.writeInt(3);
    data.writeInt(5);
    remote.sendRequest(1, data, reply, option).then((result) => {
        console.info('xxxxxx sendRequest success');
        let msg = reply.readInt();
        prompt.showToast({
            message: "onConnectLocalService connect result: " + msg,
            duration: 3000 //显示时间3s
        });
    }).catch((e) => {
        console.info('xxxxxx sendRequest error:' + e);
    });
}

function onDisconnectCallback(element){
    console.info('xxxxxx onDisconnectCallback')
}

function onFailedCallback(code){
    console.info('xxxxxx onDisconnectCallback')
}

@Entry
@Component
struct Index {
    @State message: string = 'Main'

    build() {
        Row() {
            Column() {
                Text(this.message)
                    .fontSize(50)
                    .fontWeight(FontWeight.Bold)
                Button('连接本地Service')
                    .width(500)
                    .height(80)
                    .fontSize(50)
                    .align(Alignment.Center)
                    .backgroundColor('#AD9D8F')
                    .fontColor('#FFFFFF')
                    .borderRadius(10)
                    .margin(1)
                    .onClick((event: ClickEvent) => {
                        featureAbility.connectAbility(
                            {//参数1与启动本地的FA一致
                                deviceId: "",
                                bundleName: "com.example.myohtest",
                                abilityName: "com.example.entry.ServiceAbility",
                            },
                            {//参数2为3个回调函数
                                onConnect: onConnectCallback,
                                onDisconnect: onDisconnectCallback,
                                onFailed: onFailedCallback
                            },
                        );
                    })
            }
            .width('100%')
        }
        .height('100%')
    }
}

2.连接远程的Service

连接本地的Service改成连接远程的Service需要改3个地方

1)添加远程授权的函数

async function requestPermission() {
    let array: Array<string> = ["ohos.permission.DISTRIBUTED_DATASYNC"];
    const appInfo = await bundle.getApplicationInfo('com.example.myohtest', 0, 100);
    let tokenID = appInfo.accessTokenId;
    const atManager = abilityAccessCtrl.createAtManager();
    let requestPermissions: Array<string> = [];
    for (let i = 0; i < array.length; i++) {
        let result = await atManager.verifyAccessToken(tokenID, array[i]);
        if (result != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
            requestPermissions.push(array[i]);
        }
    }
    if (requestPermissions.length == 0 || requestPermissions == []) {
        return;
    }
    let context = featureAbility.getContext();
    context.requestPermissionsFromUser(requestPermissions, 1, (data)=>{
        console.info("xxxxxx data:" + JSON.stringify(data));
    });
}

2)添加获得远程设备的Id

 deviceManager.createDeviceManager("com.example.myohtest", (err, value) => {
                            if (!err) {
                                let devManager = value;
                                deviceList = devManager.getTrustedDeviceListSync();
                                console.info('xxxxxx' + deviceList[0].deviceId);
                                this.startRemoteService();
                            }
                        });    

async startRemoteService() {
        await featureAbility.connectAbility(
            {
                deviceId: deviceList[0].deviceId,
                bundleName: "com.example.myohtest",
                abilityName: "com.example.entry.ServiceAbility"
            },
            {
                onConnect: onConnectCallback,
                onDisconnect: onDisconnectCallback,
                onFailed: onFailedCallback
            },
        );
    }

3)config.json中 Service中 加一条//必须添加,不然启动不了远程

"visible":true,

4)完整代码

import featureAbility from '@ohos.ability.featureAbility'
import prompt from '@system.prompt';
import rpc from "@ohos.rpc";
import bundle from '@ohos.bundle';
import abilityAccessCtrl from "@ohos.abilityAccessCtrl";
import deviceManager from '@ohos.distributedHardware.deviceManager';

let deviceList;	//全局定义设备列表

async function requestPermission() {
    let array: Array<string> = ["ohos.permission.DISTRIBUTED_DATASYNC"];
    const appInfo = await bundle.getApplicationInfo('com.example.myohtest', 0, 100);
    let tokenID = appInfo.accessTokenId;
    const atManager = abilityAccessCtrl.createAtManager();
    let requestPermissions: Array<string> = [];
    for (let i = 0; i < array.length; i++) {
        let result = await atManager.verifyAccessToken(tokenID, array[i]);
        if (result != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
            requestPermissions.push(array[i]);
        }
    }
    if (requestPermissions.length == 0 || requestPermissions == []) {
        return;
    }
    let context = featureAbility.getContext();
    context.requestPermissionsFromUser(requestPermissions, 1, (data)=>{
        console.info("xxxxxx data:" + JSON.stringify(data));
    });
}

async function onConnectCallback(element, remote){
    console.info('xxxxxx onConnectCallback element: ' + element);
    console.info('xxxxxx onConnectCallback remote: ' + remote);
    if (remote == null) {
        prompt.showToast({
            message: "onConnectLocalService not connected yet"
        });
        return;
    }
    let option = new rpc.MessageOption();
    let data = new rpc.MessageParcel();
    let reply = new rpc.MessageParcel();
    data.writeInt(3);
    data.writeInt(5);
    remote.sendRequest(1, data, reply, option).then((result) => {
        console.info('xxxxxx sendRequest success');
        let msg = reply.readInt();
        prompt.showToast({
            message: "onConnectLocalService connect result: " + msg,
            duration: 3000
        });
    }).catch((e) => {
        console.info('xxxxxx sendRequest error:' + e);
    });
}

async function onDisconnectCallback(element){
    console.info('xxxxxx onDisconnectCallback')
}

async function onFailedCallback(code){
    console.info('xxxxxx onDisconnectCallback')
}

@Entry
@Component
struct Index {
    @State message: string = 'Main'

    aboutToAppear(): void  {
        requestPermission();
    }

    build() {
        Row() {
            Column() {
                Text(this.message)
                    .fontSize(50)
                    .fontWeight(FontWeight.Bold)
                Button('连接本地Service')
                    .width(500)
                    .height(80)
                    .fontSize(50)
                    .align(Alignment.Center)
                    .backgroundColor('#AD9D8F')
                    .fontColor('#FFFFFF')
                    .borderRadius(10)
                    .margin(1)
                    .onClick((event: ClickEvent) => {
                        deviceManager.createDeviceManager("com.example.myohtest", (err, value) => {
                            if (!err) {
                                let devManager = value;
                                deviceList = devManager.getTrustedDeviceListSync();	//获取可信设备列表
                                console.info('xxxxxx' + deviceList[0].deviceId);
                                this.startRemoteService();
                            }
                        });
                    })
            }
            .width('100%')
        }
        .height('100%')
    }

    async startRemoteService() {
        await featureAbility.connectAbility(
            {
                deviceId: deviceList[0].deviceId,	//第一个设备
                bundleName: "com.example.myohtest",	//app名
                abilityName: "com.example.entry.ServiceAbility"	//Service
            },
            {
                onConnect: onConnectCallback,
                onDisconnect: onDisconnectCallback,
                onFailed: onFailedCallback
            },
        );
    }
}
``

## 三)分布式数据对象

分布式数据存放在内存中,如果在分布式组网环境内有多个设备,进行数据同步,那么需要让这些设备都创建分布式数据对象,并且这些对象的sessionId都是一样的。分布式数据对象的效率非常高,它存放在内存中,并没有持久化的文件或者数据库

### 1.设置sessinId

```typescript
import distributedObject from '@ohos.data.distributedDataObject';

    aboutToAppear() {
															//名字,         年龄,    是否可见	
        dod = distributedObject.createDistributedObject({name:"zhangsan", age:18, isVis: false});
        console.info("xxxxxx dod.name: " + dod.name);	//2种写法  .name 或者 ["name"]
        console.info("xxxxxx dod.age: " + dod.age);
        console.info("xxxxxx dod.isVis: " + dod.isVis);

		//distributedObject.genSessionId();  可以生成一个sessionId,但是在不同设备上生成的sessionId可能不一致,最简单的办法就是指定一个
        sessionId = "11111111";//sessionId的格式为8个数字的字符串
        dod.setSessionId(sessionId);
        console.info("xxxxxx---sessionId:" + sessionId);
    }

2.监听数据对象变更

    Button('监听数据对象变更')
          .width(500)
          .height(80)
          .fontSize(50)
          .align(Alignment.Center)
          .backgroundColor('#AD9D8F')
          .fontColor('#FFFFFF')
           .borderRadius(10)
           .onClick((event: ClickEvent)=>{
                dod.on("change", this.changeCallback.bind(this));//坑点
                console.info("xxxxxx observe change  success");
           })

changeCallback(sessionId, changeData) {
    if (changeData != null && changeData != undefined) {
        changeData.forEach(element => {
            console.info("xxxxxx---:" + "changed!" + element + "," + dod[element]);
        });
    }
}

坑点:发起方要在changeCallback里刷新界面,则需要将正确的this绑定给changeCallback

设备B想监听设备A,想把数据打印出来拿到对象不需要刷新界面,则不需要 bind(this)

设备B监听设备A,监听到数据的改变,且想要更新界面的数据,则需要 bind(this)

3.修改对象属性

Button('修改对象属性')
    .width(500)
    .height(80)
    .fontSize(50)
    .align(Alignment.Center)
    .backgroundColor('#AD9D8F')
    .fontColor('#FFFFFF')
    .borderRadius(10)
    .onClick((event: ClickEvent)=>{
    dod.name = "lisi";
    dod.age = 19;
    dod.isVis = true;
    console.info("xxxxxx update success");
})

4.读取对象数据

Button('读取对象属性')
    .width(500)
    .height(80)
    .fontSize(50)
    .align(Alignment.Center)
    .backgroundColor('#AD9D8F')
    .fontColor('#FFFFFF')
    .borderRadius(10)
    .onClick((event: ClickEvent)=>{
    console.info("xxxxxx dod.name: " + dod.name);
    console.info("xxxxxx dod.age: " + dod.age);
    console.info("xxxxxx dod.isVis: " + dod.isVis);
})

5.完整代码

import distributedObject from '@ohos.data.distributedDataObject';

let dod;
let sessionId;

@Entry
@Component
struct GridExample {
    aboutToAppear() {
															//名字,         年龄,    是否可见	
        dod = distributedObject.createDistributedObject({name:"zhangsan", age:18, isVis: false});
        console.info("xxxxxx dod.name: " + dod.name);	//2种写法  .name 或者 ["name"]
        console.info("xxxxxx dod.age: " + dod.age);
        console.info("xxxxxx dod.isVis: " + dod.isVis);

		//distributedObject.genSessionId();  可以生成一个sessionId,但是在不同设备上生成的sessionId可能不一致,最简单的办法就是指定一个
        sessionId = "11111111";//sessionId的格式为8个数字的字符串
        dod.setSessionId(sessionId);
        console.info("xxxxxx---sessionId:" + sessionId);
    }

    build() {
        Column({ space: 20 }) {
            Button('监听数据对象变更')
                .width(500)
                .height(80)
                .fontSize(50)
                .align(Alignment.Center)
                .backgroundColor('#AD9D8F')
                .fontColor('#FFFFFF')
                .borderRadius(10)
                .onClick((event: ClickEvent)=>{
                    dod.on("change", this.changeCallback.bind(this));
                    console.info("xxxxxx observe change  success");
                })

            Button('修改对象属性')
                .width(500)
                .height(80)
                .fontSize(50)
                .align(Alignment.Center)
                .backgroundColor('#AD9D8F')
                .fontColor('#FFFFFF')
                .borderRadius(10)
                .onClick((event: ClickEvent)=>{
                    dod.name = "lisi";
                    dod.age = 19;
                    dod.isVis = true;
                    console.info("xxxxxx update success");
                })

            Button('再次修改对象属性')
                .width(500)
                .height(80)
                .fontSize(50)
                .align(Alignment.Center)
                .backgroundColor('#AD9D8F')
                .fontColor('#FFFFFF')
                .borderRadius(10)
                .onClick((event: ClickEvent)=>{
                    dod.name = "wangwu";
                    dod.age = 20;
                    dod.isVis = false;
                    console.info("xxxxxx update success");
                })

            Button('读取对象属性')
                .width(500)
                .height(80)
                .fontSize(50)
                .align(Alignment.Center)
                .backgroundColor('#AD9D8F')
                .fontColor('#FFFFFF')
                .borderRadius(10)
                .onClick((event: ClickEvent)=>{
                    console.info("xxxxxx dod.name: " + dod.name);
                    console.info("xxxxxx dod.age: " + dod.age);
                    console.info("xxxxxx dod.isVis: " + dod.isVis);
                })
        }.width('100%').margin({ top: 10 })
    }

    changeCallback(sessionId, changeData) {
        if (changeData != null && changeData != undefined) {
            changeData.forEach(element => {
                console.info("xxxxxx---:" + "changed!" + element + "," + dod[element]);
            });
        }
    }
}

四)可参考的案例

1.Codelabs链接

codelabs分布式.pngimage-20220524230942785

五)小技巧

1.格式化代码

右击文件->Reformat Code 12:29

2.openHarmony的代码可以直接跑到HarmonyOS上吗?

可以,分布式数据对象HarmonyOS没有,但是import部分代码需要修改

3.代码对齐

右键ets文件,点击Reformat Code

快捷键 Ctrl+Alt+L

4.ets的2个等号与3个等号的区别

转载博客

1.===:三个等号我们称为等同符,当等号两边的值为相同类型的时候,直接比较等号两边的值,值相同则返回true,若等号两边的值类型不同时直接返回false。

 例:100===“100” //返回false
 abc===“abc”   	//返回false
 ‘abc’===“abc”  //返回true
 NaN===NaN   	//返回false
 false===false  //返回true

2.==:两个等号我们称为等值符,当等号两边的值为相同类型时比较值是否相同,类型不同时会发生类型的自动转换,转换为相同的类型后再作比较。

类型转换规则: 1)如果等号两边是boolean、string、number三者中任意两者进行比较时,优先转换为数字进行比较。 2)如果等号两边出现了null或undefined,null和undefined除了和自己相等,就彼此相等

100==“100” 	//返回true
1==true 	//返回true
“1”==“01” 	//返回false,此处等号两边值得类型相同,不要再转换类型了!!
NaN==NaN 	//返回false,NaN和所有值包括自己都不相等。

5.设备出现异常或者运行结果出现异常

建议重启,重刷系统

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

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