赞
踩
概述:
约束与限制
在HarmonyOS中,分布式任务调度平台对搭载HarmonyOS的多设备构筑的“超级虚拟终端”提供统一的组件管理能力,为应用定义统一的能力基线、接口形式、数据结构、服务描述语言,屏蔽硬件差异;支持远程启动、远程调用、业务无缝迁移等分布式任务。
分布式任务调度平台在底层实现Ability(分布式任务调度的基本组件)跨设备的启动/关闭、连接及断开连接以及迁移等能力,实现跨设备的组件管理:
开发者在应用中集成分布式调度能力,通过调用指定能力的分布式接口,实现跨设备能力调度。根据Ability模板及意图的不同,分布式任务调度向开发者提供以下六种能力:启动远程FA、启动远程PA、关闭远程PA、连接远程PA、断开连接远程PA和FA跨设备迁移。下面以设备A(本地设备)和设备B(远端设备)为例,进行场景介绍:
分布式调度平台提供的连接和断开连接PA、启动远程FA、启动和关闭PA以及迁移FA的能力,是实现更多价值性场景的基础。
连接远程PA
connectAbility(Intent intent, IAbilityConnection conn)接口提供连接指定设备上PA的能力,Intent中指定待连接PA的设备deviceId、bundleName和abilityName。当连接成功后,通过在conn定义的onAbilityConnectDone回调中获取对端PA的服务代理,两者的连接关系则由conn维护。具体的参数定义如下表所示:
参数名 | 类型 | 说明 |
---|---|---|
intent | ohos.aafwk.content.Intent | 开发者需在intent对应的Operation中指定待连接PA的设备deviceId、bundleName和abilityName。 |
conn | ohos.aafwk.ability.IAbilityConnection | 当连接成功或失败时,作为连接关系的回调接口。该接口提供连接完成和断开连接完成时的处理逻辑,开发者可根据具体的场景进行定义。 |
启动远程FA/PA
startAbility(Intent intent)接口提供启动指定设备上FA和PA的能力,Intent中指定待启动FA/PA的设备deviceId、bundleName和abilityName。具体参数定义如下表所示:
参数名 | 类型 | 说明 |
---|---|---|
intent | ohos.aafwk.content.Intent | 当开发者需要调用该接口启动远程PA时,需要指定待启动PA的设备deviceId、bundleName和abilityName。若不指定设备deviceId,则无法跨设备调用PA。 类似地,在启动FA时,也需要开发者指定启动FA的设备deviceId、bundleName和abilityName。 |
分布式调度平台还会提供与上述功能相对应的断开远程PA的连接和关闭远程PA的接口,相关的参数与连接、启动的接口类似。
迁移FA
continueAbility(String deviceId)接口提供将本地FA迁移到指定设备上的能力,需要开发者在调用时指定目标设备的deviceId。具体参数定义如下表所示:
说明
Ability和AbilitySlice类均需要实现IAbilityContinuation及其方法,才可以实现FA迁移。
参数名 | 类型 | 说明 |
---|---|---|
deviceId | String | 当开发者需要调用该接口将本地FA迁移时,需要指定目标设备的deviceId。 |
- // 以下依赖包含分布式调度平台开放的接口,用于:连接/断开连接远程PA、启动远程FA、通过连接关系注册的回调函数onAbilityConnectDone中返回的对端PA的代理,实现对PA的控制
- import ohos.aafwk.ability.AbilitySlice;
- import ohos.aafwk.ability.IAbilityConnection;
- import ohos.aafwk.content.Intent;
- import ohos.aafwk.content.Operation;
- import ohos.bundle.ElementName;
- // 为了实现迁移能力,需要引入传递迁移所需数据的包以及实现迁移能力的接口。
- import ohos.aafwk.ability.IAbilityContinuation;
- import ohos.aafwk.content.IntentParams;
- // 为了实现跨设备指令及数据通信,需要集成HarmonyOS提供的RPC接口
- import ohos.rpc.IRemoteObject;
- import ohos.rpc.IRemoteBroker;
- import ohos.rpc.MessageParcel;
- import ohos.rpc.MessageOption;
- import ohos.rpc.RemoteException;
- import ohos.rpc.RemoteObject;
- //(可选)多设备场景下涉及设备选择,为此需要引入组网设备发现的能力
- import ohos.distributedschedule.interwork.DeviceInfo;
- import ohos.distributedschedule.interwork.DeviceManager;
- // (可选)设计界面相关的包函数,对FA界面及按钮进行绘制
- import ohos.agp.components.Button;
- import ohos.agp.components.Component;
- import ohos.agp.components.Component.ClickedListener;
- import ohos.agp.components.ComponentContainer.LayoutConfig;
- import ohos.agp.components.element.ShapeElement;
- import ohos.agp.components.PositionLayout;
- // 调用AbilitySlice模板实现一个用于控制基础功能的FA
- // Ability和AbilitySlice类均需要实现IAbilityContinuation及其方法,才可以实现FA迁移。AbilitySlice的代码示例如下
- public class SampleSlice extends AbilitySlice implements IAbilityContinuation {
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- // 开发者可以自行进行界面设计
- // 为按钮设置统一的背景色
- // 例如通过PositionLayout指定大小可以实现简单界面
- PositionLayout layout = new PositionLayout(this);
- LayoutConfig config = new LayoutConfig(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_PARENT);
- layout.setLayoutConfig(config);
- ShapeElement buttonBg = new ShapeElement();
- buttonBg.setRgbColor(new RgbColor(0,125,255));
- addComponents(layout, buttonBg, config);
- super.setUIContent(layout);
- }
-
- @Override
- public void onInactive() {
- super.onInactive();
- }
-
- @Override
- public void onActive() {
- super.onActive();
- }
-
- @Override
- public void onBackground() {
- super.onBackground();
- }
-
- @Override
- public void onForeground(Intent intent) {
- super.onForeground(intent);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- }
- }
说明
此步骤展示了一个简单FA的实现过程,实际开发中请开发者根据需要进行设计。
- {
- "reqPermissions": [
- {
- "name": "ohos.permission.DISTRIBUTED_DATASYNC"
- }
- ]
- }
此外,对于三方应用还要求在实现Ability的代码中显式声明需要使用的权限,如下所示:
- public class SampleSlice extends AbilitySlice implements IAbilityContinuation {
- @Override
- public void onStart(Intent intent) {
- // 开发者显示声明需要使用的权限
- requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC"}, 0);
- super.onStart(intent);
- }
- }
- // 建议开发者按照自己的界面进行按钮设计
- // 开发者可以自行实现如createButton的方法,新建一个显示文字text,背景色为buttonBg以及大小尺寸位置符合config设置的按钮,用来与用户发生交互
- // private Button createButton(String text, ShapeElement buttonBg, LayoutConfig config)
- // 按照顺序在PositionLayout中依次添加按钮的示例
- private void addComponents(PositionLayout linear, ShapeElement buttonBg, LayoutConfig config) {
- // 构建远程启动FA的按钮
- btnStartRemoteFA = createButton("StartRemoteFA", buttonBg, config);
- btnStartRemoteFA.setClickedListener(mStartRemoteFAListener);
- linear.addComponent(btnStartRemoteFA);
- // 构建远程启动PA的按钮
- btnStartRemotePA = createButton("StartRemotePA", buttonBg, config);
- btnStartRemotePA.setClickedListener(mStartRemotePAListener);
- linear.addComponent(btnStartRemotePA);
- // 构建远程关闭PA的按钮
- btnStopRemotePA = createButton("StopRemotePA", buttonBg, config);
- btnStopRemotePA.setClickedListener(mStopRemotePAListener);
- linear.addComponent(btnStopRemotePA);
- // 构建连接远程PA的按钮
- btnConnectRemotePA = createButton("ConnectRemotePA", buttonBg, config);
- btnConnectRemotePA.setClickedListener(mConnectRemotePAListener);
- linear.addComponent(btnConnectRemotePA);
- // 构建控制连接PA的按钮
- btnControlRemotePA = createButton("ControlRemotePA", buttonBg, config);
- btnControlRemotePA.setClickedListener(mControlPAListener);
- linear.addComponent(btnControlRemotePA);
- // 构建与远程PA断开连接的按钮
- btnDisconnectRemotePA = createButton("DisconnectRemotePA", buttonBg, config);
- btnDisconnectRemotePA.setClickedListener(mDisconnectRemotePAListener);
- linear.addComponent(btnDisconnectRemotePA);
- // 构建迁移FA的按钮
- btnContinueRemoteFA = createButton("ContinueRemoteFA", buttonBg, config);
- btnContinueRemoteFA.setClickedListener(mContinueAbilityListener);
- linear.addComponent(btnContinueRemoteFA);
- }
说明
此处只展示了基于按钮控制的能力调度方法,实际开发中请开发者根据需要选择能力调度方式。代码示例中未体现按钮如位置、样式等具体的设置方法,详请参考JAVA UI框架。
- {
- "reqPermissions": [
- {
- "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
- },
- {
- "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
- },
- {
- "name": "ohos.permission.GET_BUNDLE_INFO"
- }
- ]
- }
下述实例中涉及对在线组网设备的查询,该项能力需要开发者在对应的config.json中声明获取设备列表及设备信息的权限,如下所示:
- // ISelectResult是一个自定义接口,用来处理指定设备deviceId后执行的行为
- interface ISelectResult {
- void onSelectResult(String deviceId);
- }
-
- // 获得设备列表,开发者可在得到的在线设备列表中选择目标设备执行操作
- private void scheduleRemoteAbility(ISelectResult listener) {
- // 调用DeviceManager的getDeviceList接口,通过FLAG_GET_ONLINE_DEVICE标记获得在线设备列表
- List<DeviceInfo> onlineDevices = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
- // 判断组网设备是否为空
- if (onlineDevices.isEmpty()) {
- listener.onSelectResult(null);
- return;
- }
- int numDevices = onlineDevices.size();
- ArrayList<String> deviceIds = new ArrayList<>(numDevices);
- ArrayList<String> deviceNames = new ArrayList<>(numDevices);
- onlineDevices.forEach((device) -> {
- deviceIds.add(device.getDeviceId());
- deviceNames.add(device.getDeviceName());
- });
- // 以选择首个设备作为目标设备为例
- // 开发者也可按照具体场景,通过别的方式进行设备选择
- String selectDeviceId = deviceIds.get(0);
- listener.onSelectResult(selectDeviceId);
- }
- // 启动一个指定bundleName和abilityName的FA
- private ClickedListener mStartRemoteFAListener = new ClickedListener() {
- @Override
- public void onClick(Component arg0) {
- // 启动远程PA
- scheduleRemoteAbility(new ISelectResult() {
- @Override
- void onSelectResult(String deviceId) {
- if (deviceId != null) {
- Intent intent = new Intent();
- // 通过scheduleRemoteAbility指定目标设备deviceId
- // 指定待启动FA的bundleName和abilityName
- // 例如:bundleName = "com.huawei.helloworld"
- // abilityName = "com.huawei.helloworld.SampleFeatureAbility"
- // 设置分布式标记,表明当前涉及分布式能力
- Operation operation = new Intent.OperationBuilder()
- .withDeviceId(deviceId)
- .withBundleName(bundleName)
- .withAbilityName(abilityName)
- .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
- .build();
- intent.setOperation(operation);
- // 通过AbilitySlice包含的startAbility接口实现跨设备启动FA
- startAbility(intent);
- }
- }
- });
- }
- };
对于PA的启动、关闭、连接等操作都需要开发者提供目标设备的deviceId。开发者可以通过DeviceManager相关接口得到当前组网下的设备列表,并以弹窗的形式供用户选择,也可以按照实际需要实现其他个性化的处理方式。在点击事件回调函数中,需要开发者指定得到deviceId后的处理逻辑,即实现类似上例中listener.onSelectResult(String deviceId)的方法,代码示例如下:
- // 启动远程PA
- private ClickedListener mStartRemotePAListener = new ClickedListener() {
- @Override
- public void onClick(Component arg0) {
- // 启动远程PA
- scheduleRemoteAbility(new ISelectResult() {
- @Override
- void onSelectResult(String deviceId) {
- if (deviceId != null) {
- Intent intentToStartPA = new Intent();
- // bundleName和abilityName与待启动PA对应
- // 例如:bundleName = "com.huawei.helloworld"
- // abilityName = "com.huawei.helloworld.SampleParticleAbility"
- Operation operation = new Intent.OperationBuilder()
- .withDeviceId(deviceId)
- .withBundleName(bundleName)
- .withAbilityName(abilityName)
- .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
- .build();
- intentToStartPA.setOperation(operation);
- startAbility(intentToStartPA);
- }
- }
- });
- }
- };
-
- // 关闭远程PA,和启动类似开发者需要指定待关闭PA对应的bundleName和abilityName
- private ClickedListener mStopRemotePAListener = new ClickedListener() {
- @Override
- public void onClick(Component arg0) {
- scheduleRemoteAbility(new ISelectResult() {
- @Override
- void onSelectResult(String deviceId) {
- if (deviceId != null) {
- Intent intentToStopPA = new Intent();
- // bundleName和abilityName与待关闭PA对应
- // 例如:bundleName = "com.huawei.helloworld"
- // abilityName = "com.huawei.helloworld.SampleParticleAbility"
- Operation operation = new Intent.OperationBuilder()
- .withDeviceId(deviceId)
- .withBundleName(bundleName)
- .withAbilityName(abilityName)
- .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
- .build();
- intentToStopPA.setOperation(operation);
- stopAbility(intentToStopPA);
- }
- }
- });
- }
- };
说明
启动和关闭的行为类似,开发者只需在Intent中指定待调度PA的deviceId、bundleName和abilityName,并以operation的形式封装到Intent内。通过AbilitySlice(Ability)包含的startAbility()和stopAbility()接口即可实现相应功能。
- // 当连接完成时,用来提供管理已连接PA的能力
- private MyRemoteProxy mProxy = null;
- // 用于管理连接关系
- private IAbilityConnection conn = new IAbilityConnection() {
- @Override
- public void onAbilityConnectDone(ElementName element, IRemoteObject remote, int resultCode) {
- // 跨设备PA连接完成后,会返回一个序列化的IRemoteObject对象
- // 通过该对象得到控制远端服务的代理
- mProxy = new MyRemoteProxy(remote);
- btnConnectRemotePA.setText("connectRemoteAbility done");
- }
-
- @Override
- public void onAbilityDisconnectDone(ElementName element, int resultCode) {
- // 当已连接的远端PA关闭时,会触发该回调
- // 支持开发者按照返回的错误信息进行PA生命周期管理
- disconnectAbility(conn);
- }
- };
仅通过启动/关闭两种方式对PA进行调度无法应对需长期交互的场景,因此,分布式任务调度平台向开发者提供了跨设备PA连接及断开连接的能力。为了对已连接PA进行管理,开发者需要实现一个满足IAbilityConnection接口的连接状态检测实例,通过该实例可以对连接及断开连接完成时设置具体的处理逻辑,例如:获取控制对端PA的代理等。进一步为了使用该代理跨设备调度PA,开发者需要在本地及对端分别实现对外接口一致的代理。一个具备加法能力的代理示例如下: - // 以连接提供加法计算能力的PA为例。为了提供跨设备连接能力,需要在本地发起连接侧和对端被连接侧分别实现代理。
- // 发起连接侧的代理示例如下
- public class MyRemoteProxy implements IRemoteBroker{
- private static final int ERR_OK = 0;
- private static final int COMMAND_PLUS = IRemoteObject.MIN_TRANSACTION_ID;
- private final IRemoteObject remote;
-
- public MyRemoteProxy(
- /* [in] */ IRemoteObject remote) {
- this.remote = remote;
- }
-
- @Override
- public IRemoteObject asObject() {
- return remote;
- }
-
- public int plus(
- /* [in] */ int a,
- /* [in] */ int b) throws RemoteException {
- MessageParcel data = MessageParcel.obtain();
- MessageParcel reply = MessageParcel.obtain();
- // option不同的取值,决定采用同步或异步方式跨设备控制PA
- // 本例需要同步获取对端PA执行加法的结果,因此采用同步的方式,即MessageOption.TF_SYNC
- // 具体MessageOption的设置,可参考相关API文档
- MessageOption option = new MessageOption(MessageOption.TF_SYNC);
- data.writeInt(a);
- data.writeInt(b);
-
- try {
- remote.sendRequest(COMMAND_PLUS, data, reply, option);
- int ec = reply.readInt();
- if (ec != ERR_OK) {
- throw new RemoteException();
- }
- int result = reply.readInt();
- return result;
- } catch (RemoteException e) {
- throw new RemoteException();
- } finally {
- data.reclaim();
- reply.reclaim();
- }
- }
- }
此外,对端待连接的PA需要实现对应的客户端,代码示例如下所示:
- // 以计算加法为例,对端实现的客户端如下
- public class MyRemote extends RemoteObject implements IRemoteBroker{
- private static final int ERR_OK = 0;
- private static final int ERROR = -1;
- private static final int COMMAND_PLUS = IRemoteObject.MIN_TRANSACTION_ID;
-
- public MyRemote() {
- super("MyService_Remote");
- }
-
- @Override
- public IRemoteObject asObject() {
- return this;
- }
-
- @Override
- public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
- if (code != COMMAND_PLUS) {
- reply.writeInt(ERROR);
- return false;
- }
- int value1 = data.readInt();
- int value2 = data.readInt();
- int sum = value1 + value2;
- reply.writeInt(ERR_OK);
- reply.writeInt(sum);
- return true;
- }
- }
对端除了要实现如上所述的客户端外,待连接的PA还需要作如下修改: - // 为了返回给连接方可调用的代理,需要在该PA中实例化客户端,例如作为该PA的成员变量
- private MyRemote remote = new MyRemote();
- // 当该PA接收到连接请求时,即将该客户端转化为代理返回给连接发起侧
- @Override
- protected IRemoteObject onConnect(Intent intent) {
- super.onConnect(intent);
- return remote.asObject();
- }
完成上述步骤后,可以通过点击事件实现连接、利用连接关系控制PA以及断开连接等行为,代码示例如下: - // 连接远程PA
- private ClickedListener mConnectRemotePAListener = new ClickedListener() {
- @Override
- public void onClick(Component arg0) {
- scheduleRemoteAbility(new ISelectResult() {
- @Override
- void onSelectResult(String deviceId) {
- if (deviceId != null) {
- Intent connectPAIntent = new Intent();
- // bundleName和abilityName与待连接的PA一一对应
- // 例如:bundleName = "com.huawei.helloworld"
- // abilityName = "com.huawei.helloworld.SampleParticleAbility"
- Operation operation = new Intent.OperationBuilder()
- .withDeviceId(deviceId)
- .withBundleName(bundleName)
- .withAbilityName(abilityName)
- .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
- .build();
- connectPAIntent.setOperation(operation);
- connectAbility(connectPAIntent, conn);
- }
- }
- });
- }
- };
- // 控制已连接PA执行加法
- private ClickedListener mControlPAListener = new ClickedListener() {
- @Override
- public void onClick(Component arg0) {
- if (mProxy != null) {
- int ret = -1;
- try {
- ret = mProxy.plus(10, 20);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- btnControlRemotePA.setText("ControlRemotePA result = " + ret);
- }
- }
- };
- // 与远程PA断开连接
- private ClickedListener mDisconnectRemotePAListener = new ClickedListener() {
- @Override
- public void onClick(Component arg0) {
- // 按钮复位
- btnConnectRemotePA.setText("ConnectRemotePA");
- btnControlRemotePA.setText("ControlRemotePA");
- disconnectAbility(conn);
- }
- };
说明
通过连接/断开连接远程PA,与跨设备PA建立长期的管理关系。例如在本例中,通过连接关系得到远程PA的控制代理后,实现跨设备计算加法并将结果返回到本地显示。在实际开发中,开发者可以根据需要实现多种分布式场景,例如:跨设备位置/电量等信息的采集、跨设备计算资源互助等。
说明
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。