文章40 | 阅读 20977 | 点赞0
在 HarmonyOS 中,分布式任务调度平台对搭载 HarmonyOS 的多设备构筑的“超级虚拟终端”提供统一的组件管理能力,为应用定义统一的能力基线、接口形式、数据结构、服务描述语言,屏蔽硬件差异;支持远程启动、远程调用、业务无缝迁移等分布式任务。
分布式任务调度平台在底层实现 Ability(分布式任务调度的基本组件)跨设备的启动/关闭、连接及断开连接以及迁移等能力,实现跨设备的组件管理:
启动和关闭:向开发者提供管理远程 Ability 的能力,即支持启动 Page 模板的 Ability,以及启动、关闭 Service 和 Data 模板的 Ability。
连接和断开连接:向开发者提供跨设备控制服务(Service 和 Data 模板的 Ability)的能力,开发者可以通过与远程服务连接及断开连接实现获取或注销跨设备管理服务的对象,达到和本地一致的服务调度。
迁移能力:向开发者提供跨设备业务的无缝迁移能力,开发者可以通过调用 Page 模板 Ability 的迁移接口,将本地业务无缝迁移到指定设备中,打通设备间壁垒。
参数名 | 类型 | 说明 |
---|---|---|
intent | ohos.aafwk.content.Intent | 开发者需在intent对应的Operation中指定待连接PA的设备deviceId、bundleName和abilityName |
conn | ohos.aafwk.ability.IAbilityConnection | 当连接成功或失败时,作为连接关系的回调接口。该接口提供连接完成和断开连接完成时的处理逻辑,开发者可根据具体的场景进行定义 |
参数名 | 类型 | 说明 |
---|---|---|
intent | ohos.aafwk.content.Intent | 当开发者需要调用该接口启动远程PA时,需要指定待启动PA的设备deviceId、bundleName和abilityName。若不指定设备deviceId,则无法跨设备调用PA。类似地,在启动FA时,也需要开发者指定启动FA的设备deviceId、bundleName和abilityName |
参数名 | 类型 | 说明 |
---|---|---|
deviceId | String | 当开发者需要调用该接口将本地FA迁移时,需要指定目标设备的deviceId |
// 以下依赖包含分布式调度平台开放的接口
// 用于:连接/断开连接远程PA、启动远程FA、通过连接关系实现对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;
// 为了实现跨设备指令及数据通信,需要使用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,AbilitySlice的代码示例如下:
public class SampleSlice extends AbilitySlice {
@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();
}
}
{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
},
{
...
}
]
}
}
public class SampleSlice extends AbilitySlice {
@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);
}
// 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();
List<String> deviceIds = new ArrayList<>(numDevices);
onlineDevices.forEach((device) -> {
deviceIds.add(device.getDeviceId());
});
// 以选择首个设备作为目标设备为例
// 开发者也可按照具体场景,通过别的方式进行设备选择
String selectDeviceId = deviceIds.get(0);
listener.onSelectResult(selectDeviceId);
}
{
"reqPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
},
{
"name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
},
{
"name": "ohos.permission.GET_BUNDLE_INFO"
}
]
}
// 启动一个指定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) {
// 通过scheduleRemoteAbility指定目标设备deviceId
// 指定待启动FA的bundleName和abilityName
// 例如:bundleName = "com.helloworld"
// abilityName = "com.helloworld.SampleFeatureAbility"
// 设置分布式标记,表明当前涉及分布式能力
Operation operation = new Intent.OperationBuilder()
.withDeviceId(deviceId)
.withBundleName(bundleName)
.withAbilityName(abilityName)
.withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
.build();
Intent intent = new Intent();
intent.setOperation(operation);
// 通过AbilitySlice包含的startAbility接口实现跨设备启动FA
startAbility(intent);
}
}
});
}
};
// 启动远程PA
private ClickedListener mStartRemotePAListener = new ClickedListener() {
@Override
public void onClick(Component arg0) {
// 启动远程PA
scheduleRemoteAbility(new ISelectResult() {
@Override
void onSelectResult(String deviceId) {
if (deviceId != null) {
// bundleName和abilityName与待启动PA对应
// 例如:bundleName = "com.helloworld"
// abilityName = "com.helloworld.SampleParticleAbility"
Operation operation = new Intent.OperationBuilder()
.withDeviceId(deviceId)
.withBundleName(bundleName)
.withAbilityName(abilityName)
.withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
.build();
Intent intentToStartPA = new Intent();
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) {
// bundleName和abilityName与待关闭PA对应
// 例如:bundleName = "com.helloworld"
// abilityName = "com.helloworld.SampleParticleAbility"
Operation operation = new Intent.OperationBuilder()
.withDeviceId(deviceId)
.withBundleName(bundleName)
.withAbilityName(abilityName)
.withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
.build();
Intent intentToStopPA = new Intent();
intentToStopPA.setOperation(operation);
stopAbility(intentToStopPA);
}
}
});
}
};
// 当连接完成时,用来提供管理已连接PA的能力
private MyRemoteProxy mProxy = null;
// 用于管理连接关系
private IAbilityConnection mConn = 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(mConn);
}
};
// 以连接提供加法计算能力的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(IRemoteObject remote) {
this.remote = remote;
}
@Override
public IRemoteObject asObject() {
return remote;
}
public int plus(int a, 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 errCode = reply.readInt();
if (errCode != ERR_OK) {
throw new RemoteException();
}
int result = reply.readInt();
return result;
}
finally {
data.reclaim();
reply.reclaim();
}
}
}
// 以计算加法为例,对端实现的客户端如下
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的成员变量
private MyRemote remote = new MyRemote();
// 当该PA接收到连接请求时,即将该客户端转化为代理返回给连接发起侧
@Override
protected IRemoteObject onConnect(Intent intent) {
super.onConnect(intent);
return remote.asObject();
}
// 连接远程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.helloworld"
// abilityName = "com.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, mConn);
}
}
});
}
};
// 控制已连接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) {
HiLog.error(LABEL, "ControlRemotePA error");
}
btnControlRemotePA.setText("ControlRemotePA result = " + ret);
}
}
};
// 与远程PA断开连接
private ClickedListener mDisconnectRemotePAListener = new ClickedListener() {
@Override
public void onClick(Component arg0) {
// 按钮复位
btnConnectRemotePA.setText("ConnectRemotePA");
btnControlRemotePA.setText("ControlRemotePA");
disconnectAbility(mConn);
}
};
// 跨设备迁移FA
// 本地FA设置当前运行任务
private ClickedListener mContinueAbilityListener = new ClickedListener() {
@Override
public void onClick(Component arg0) {
// 用户选择设备后实现业务迁移
scheduleRemoteAbility(new ISelectResult() {
@Override
public void onSelectResult(String deviceId) {
continueAbility(deviceId);
}
});
}
};
public class SampleSlice extends AbilitySlice implements IAbilityContinuation {
@Override
public boolean onSaveData(IntentParams saveData) {
String exampleData = String.valueOf(System.currentTimeMillis());
saveData.setParam("continueParam", exampleData);
return true;
}
@Override
public boolean onRestoreData(IntentParams restoreData) {
// 远端FA迁移传来的状态数据,开发者可以按照特定的场景对这些数据进行处理
Object data = restoreData.getParam("continueParam");
return true;
}
@Override
public void onCompleteContinuation(int result) {
btnContinueRemoteFA.setText("ContinueAbility Done");
}
}
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/Forever_wj/article/details/118052602
内容来源于网络,如有侵权,请联系作者删除!