鸿蒙开发【分布式任务调度】解析

鸿蒙OS 分布式任务调度概述

在 HarmonyO S中,分布式任务调度平台对搭载 HarmonyOS 的多设备构筑的“超级虚拟终端”提供统一的组件管理能力,为应用定义统一的能力基线、接口形式、数据结构、服务描述语言,屏蔽硬件差异;支持远程启动、远程调用、业务无缝迁移等分布式任务。

分布式任务调度平台在底层实现 Ability(分布式任务调度的基本组件)跨设备的启动/关闭、连接及断开连接以及迁移等能力,实现跨设备的组件管理:

  • 启动和关闭:向开发者提供管理远程 Ability 的能力,即支持启动 Page 模板的 Ability,以及启动、关闭 Service 和 Data 模板的 Ability。
  • 连接和断开连接:向开发者提供跨设备控制服务( Service 和 Data 模板的 Ability )的能力,开发者可以通过与远程服务连接及断开连接实现获取或注销跨设备管理服务的对象,达到和本地一致的服务调度。
  • 迁移能力:向开发者提供跨设备业务的无缝迁移能力,开发者可以通过调用 Page 模板 Ability 的迁移接口,将本地业务无缝迁移到指定设备中,打通设备间壁垒。

约束与限制

  • 开发者需要在 Intent 中设置支持分布式的标记(例如:Intent.FLAG_ABILITYSLICE_MULTI_DEVICE 表示该应用支持分布式调度),否则将无法获得分布式能力。
  • 开发者通过在 config.json 中添加分布式数据传输的权限申请:{“name”: “ohos.permission.servicebus.ACCESS_SERVICE”},获取跨设备连接的能力。
  • PA( Particle Ability,Service 和 Data 模板的 Ability)的调用支持连接及断开连接、启动及关闭这四类行为,在进行调度时:
  • 开发者必须在 Intent 中指定 PA 对应的 bundleName 和 abilityName。
  • 当开发者需要跨设备启动、关闭或连接 PA 时,需要在 Intent 中指定对端设备的 deviceId。开发者可通过如设备管理类 DeviceManager 提供的 getDeviceList 获取指定条件下匿名化处理的设备列表,实现对指定设备 PA 的启动/关闭以及连接管理。
  • FA(Feature Ability,Page 模板的 Ability)的调用支持启动和迁移行为,在进行调度时:
  • 当启动 FA 时,需要开发者在 Intent 中指定对端设备的 deviceId、bundleName 和 abilityName。
  • FA 的迁移实现相同 bundleName 和 abilityName 的 FA 跨设备迁移,因此需要指定迁移设备的 deviceId。

鸿蒙OS 发布式任务调度开发指导

场景介绍

开发者在应用中集成分布式调度能力,通过调用指定能力的分布式接口,实现跨设备能力调度。根据 Ability 模板及意图的不同,分布式任务调度向开发者提供以下六种能力:启动远程 FA、启动远程 PA、关闭远程 PA、连接远程 PA、断开连接远程 PA 和 FA 跨设备迁移。下面以设备 A(本地设备)和设备 B(远端设备)为例,进行场景介绍:

  • 设备 A 启动设备 B 的 FA:在设备 A 上通过本地应用提供的启动按钮,启动设备 B 上对应的 FA。例如:设备 A 控制设备 B 打开相册,只需开发者在启动 FA 时指定打开相册的意图即可。
  • 设备 A 启动设备 B 的 PA:在设备 A 上通过本地应用提供的启动按钮,启动设备 B 上指定的 PA。例如:开发者在启动远程服务时通过意图指定音乐播放服务,即可实现设备 A 启动设备 B 音乐播放的能力。
  • 设备 A 关闭设备 B 的 PA:在设备 A 上通过本地应用提供的关闭按钮,关闭设备 B 上指定的 PA。类似启动的过程,开发者在关闭远程服务时通过意图指定音乐播放服务,即可实现关闭设备 B 上该服务的能力。
  • 设备 A 连接设备 B 的 PA:在设备 A 上通过本地应用提供的连接按钮,连接设备 B 上指定的 PA。连接后,通过其他功能相关按钮实现控制对端 PA 的能力。通过连接关系,开发者可以实现跨设备的同步服务调度,实现如大型计算任务互助等价值场景。
  • 设备 A 与设备 B 的 PA 断开连接:在设备 A 上通过本地应用提供断开连接的按钮,将之前已连接的 PA 断开连接。
  • 设备 A 的 FA 迁移至设备B:设备 A 上通过本地应用提供的迁移按钮,将设备 A 的业务无缝迁移到设备B中。通过业务迁移能力,打通设备 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 的接口,相关的参数与连接、启动的接口类似。

1.断开远程 PA 连接:disconnectAbility (IAbilityConnection conn)。 2.关闭远程 PA:boolean stopAbility (Intent intent)。

  • 迁移FA

continueAbility(String deviceId)接口提供将本地FA迁移到指定设备上的能力,需要开发者在调用时指定目标设备的 deviceId。具体参数定义如下表所示:

说明

Ability 和 AbilitySlice 类均需要实现 IAbilityContinuation 及其方法,才可以实现 FA 迁移。

参数名

类型

说明

deviceId

String

当开发者需要调用该接口将本地 FA 迁移时,需要指定目标设备的 deviceId。

开发步骤

  • 导入功能依赖的包。
// 以下依赖包含分布式调度平台开放的接口,用于:连接/断开连接远程 PA、启动远程 FA、通过连接关系注册的回调函数 onAbilityConnectDon e中返回的对端 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;
  • (可选)编写一个基本的 FA 用于使用分布式能力。
// 调用 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 的实现过程,实际开发中请开发者根据需要进行设计。

  • (可选)为不同的能力设置相应的控制按钮。
// 建议开发者按照自己的界面进行按钮设计
   // 开发者可以自行实现如 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框架。

  • 通过设备管理 DeviceManager 提供的 getDeviceList 接口获取设备列表,用于指定目标设备。
// 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);    
   }

上述实例中涉及对在线组网设备的查询,该项能力需要开发者在对应的 config.json 中声明获取设备列表及设备信息的权限,如下所示:

{
       "reqPermissions": [
           {
               "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
           }, 
           {
               "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
           }, 
           {
               "name": "ohos.permission.GET_BUNDLE_INFO"
           }
       ]
   }
  • 为启动远程 FA 的按钮设置点击回调,实现启动远程 FA 的能力。
// 启动一个指定 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 定义回调,实现启动和关闭 PA 的能力。

对于 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()接口即可实现相应功能。

  • 设备 A 连接设备 B 侧的 PA,利用连接关系调用该 PA 执行特定任务,以及断开连接。
// 当连接完成时,用来提供管理已连接 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 MyProxy remote = new MyProxy();
   // 当该 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 的控制代理后,实现跨设备计算加法并将结果返回到本地显示。在实际开发中,开发者可以根据需要实现多种分布式场景,例如:跨设备位置/电量等信息的采集、跨设备计算资源互助等。

  • 设备 A 将运行时的 FA 迁移到设备 B,实现业务在设备间无缝迁移。
// 跨设备迁移FA
   // 本地FA设置当前运行任务
   private ClickedListener mContinueAbilityListener = new ClickedListener() {
       @Override
       public void onClick(Component arg0) {
           // 用户选择设备后实现业务迁移
           scheduleRemoteAbility(new ISelectResult() {
               @Override
               public void onSelectResult(String deviceId) {
                   continueAbility(deviceId);
               }
           });
       }
   };

此外,不同于启动行为,FA 的迁移还涉及到状态数据的传递。为此,继承的 IAbilityContinuation 接口为开发者提供迁移过程中特定事件的管理能力。通过自定义迁移事件相关的行为,最终实现对 Ability 的迁移。具体的定义可以参考相关的 API 文档,此处主要以较为常用的两个事件,包括迁移发起端完成迁移的回调 onCompleteContinuation(int result)以及接收到远端迁移行为传递数据的回调 onRestoreData(IntentParams restoreData)。其他还包括迁移到远端设备的 FA 关闭的回调 onRemoteTerminated()、用于本地迁移发起时保存状态数据的回调 onSaveData(IntentParams saveData)和本地发起迁移的回调 onStartContinuation()。按照实际应用自定义特定场景对应的回调,可以完成多种场景下 FA 的迁移任务。

@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");
   }

说明

1.FA 迁移可以打通设备间的壁垒,有助于不同能力的设备进行互助。前文以一个简单的例子介绍如何通过分布式任务调度提供的能力,实现 FA 跨设备的迁移(包括 FA 启动及状态数据的同步)。 2.FA 迁移过程中,远端 FA 首先接收到发起端 FA 传输的数据,再执行启动,即 onRestoreData() 发生在 onStart() 之前。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/356306.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

成功解决IndexError: index 0 is out of bounds for axis 1 with size 0.

成功解决IndexError: index 0 is out of bounds for axis 1 with size 0. &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333;报错分析及解决方案&#x1f333;&#x1f333;参考文章&#x1f333;&#x1f333;结尾&#x1f333; &#x1f333;…

Codeforces Round 921 (Div. 2)补题

We Got Everything Covered!&#xff08;Problem - A - Codeforces&#xff09; 题目大意&#xff1a;要求找出一个长度最短的字符串&#xff0c;满足任意由前k个字母组成的长度为n的字符串都是它的子序列。输出字符串。 思路&#xff1a;这道题我本来想的很简单&#xff0c;…

仅使用 Python 创建的 Web 应用程序(前端版本)第10章_订单列表

本章我们将实现订单列表页面。 完成后的图像如下。 创建过程与之前相同,如下。 No分类内容1Model创建继承BaseDataModel的数据类Order、OrderDetail2Service创建一个 OrderAPIClient3Page定义PageId并创建继承自BasePage的页面类4Application将页面 ID 和页面类对添加到 Mult…

第五季特别篇:一夜杯、游戏之宴 2017.04.26

第五季特别篇&#xff1a;一夜杯、游戏之宴 2017.04.26 OVA 第1话&#xff1a;一夜酒杯 / 一夜杯OVA 第2话&#xff1a;游戏之宴 / 遊戯の宴 OVA 第1话&#xff1a;一夜酒杯 / 一夜杯 遭到独角妖袭击的妖怪夫妇日土和初菜被夏目所救&#xff0c;这对妖怪夫妇制作的酒杯&#xf…

【服务器APP】利用HBuilder X把网页打包成APP

目录 &#x1f33a;1. 概述 &#x1f33c;1.1 新建项目 &#x1f33c;1.2 基础配置 &#x1f33c;1.3 图标配置 &#x1f33c;1.4 启动界面配置 &#x1f33c;1.5 模块配置 &#x1f33c;1.6 打包成APP &#x1f33a;1. 概述 探讨如何将网页转化为APP&#xff0c;这似乎…

LeetCode 热题 100 | 矩阵

目录 1 73. 矩阵置零 2 54. 螺旋矩阵 3 48. 旋转图像 4 240. 搜索二维矩阵 II 菜鸟做题第二周&#xff0c;语言是 C 1 73. 矩阵置零 解题思路&#xff1a; 遍历矩阵&#xff0c;寻找等于 0 的元素&#xff0c;记录对应的行和列将被记录的行的元素全部置 0将被记录的…

SOME/IP 协议介绍(七)传输 CAN 和 FlexRay 帧

SOME/IP 不应仅用于传输 CAN 或 FlexRay 帧。但是&#xff0c;消息 ID 空间需要在两种用例之间进行协调。 传输 CAN/FlexRay 应使用完整的 SOME/IP 标头。 AUTOSAR Socket-Adapter 使用消息 ID 和长度来构建所需的内部 PDU&#xff0c;但不会查看其他字段。因此&#xff0c;必…

「效果图渲染」如何使用VRay渲染逼真的物理模型

使用V-Ray渲染出逼真的物理模型首先要注重材质和光照的真实性。精细调整材质属性&#xff0c;如反射、透明度和质感&#xff0c;确保它们与现实世界中物质的特性相一致。接下来&#xff0c;布置合适的光源&#xff0c;模拟自然光线的行为&#xff0c;创建真实的光影效果。通过这…

Redis -- 前置知识

目录 简要 分布式系统 负载均衡 引入缓存 数据库分表 微服务 小结 简要 redis是存储数据在内存中, 定义变量就是在内存中, 但是redis是在分布式系统中, 才能真正发挥威力, 如果只是单机程序, 那么直接通过变量来存储数据的方式将是最优的选择. …

(bean的创建图)学习Spring的第十天(很重要)

大致框架按如下 第一次细分 bean对象还未创建 操作第一个map 引入BeanFactoryPostProcessor , 即Bean工厂后处理器 , 为Spring很重要的扩展点 BeanFactoryPostProcessor内部的方法 可以对BeaDefinition进行修改 , 也可进行BeanDefinition的注册 ( 原有在xml文件配置的bean…

大模型学习与实践笔记(十四)

使用 OpenCompass 评测 InternLM2-Chat-7B 模型使用 LMDeploy 0.2.0 部署后在 C-Eval 数据集上的性能 步骤1&#xff1a;下载internLM2-Chat-7B 模型,并进行挂载 以下命令将internlm2-7b模型挂载到当前目录下&#xff1a; ln -s /share/model_repos/internlm2-7b/ ./ 步骤2&…

idea docker 内网应用实践

文章目录 前言一、服务器端1.1 离线安装docker1.2 开启docker远程访问1.3 制作对应jdk镜像1.3.1 下载jdk171.3.2 Dockerfile 制作jdk17镜像1.3.3 镜像导出1.3.4 服务器引入镜像 二、Idea 配置2.1 Dockerfile2.2 pom 引入docker插件2.3 idea docker插件配置2.4 打包镜像上传2.5 …

UE5在VisualStudio升级后产生C++无法编译的问题

往期的虚幻引擎项目在VS更新后&#xff0c;编译时会报错&#xff0c;这一般出现在VS升级之后&#xff0c;UE对于VC的编译器定位没有更新导致&#xff1b; 有出现如下问题&#xff1a; 问题1&#xff1a; Running I:/EPCI/Epic Games/UE_5.3/Engine/Build/BatchFiles/Build.ba…

Python采集微博评论数据,让评论告诉我们最近热议话题

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 环境使用: Python 3.10 Pycharm 模块使用: import requests >>> pip install requests import csv 模块安装&#xff1a; win R 输入cmd 输入安…

echarts option series smooth

echarts option series smooth 平滑处理 smooth&#xff1a;0.3 echarts_04_line.html <!DOCTYPE html> <html lang"en"><head> <meta charset"utf-8"> <title></title> </head><body><div id&quo…

蓝桥杯省赛无忧 课件51 第6次学长直播带练配套课件

01 最小的或运算 02 简单的异或难题 03 出列 04 异或森林 05 位移 06 笨笨的机器人 07 迷失的数 08 最大通过数

0128-2-keep-alive组件

&#x1f4bb;1、keep-alive是什么&#xff1f; keep-alive是Vue内置的一个组件&#xff0c;可以使被包含的组件保留状态&#xff0c;避免被重新渲染&#xff01;可以理解成防弹衣&#x1f9e5;; 包含在keep-alive里面的组件&#xff0c;所有路径匹配到的视图都会被缓存。 <…

Python字符串常用操作

在Python编程中&#xff0c;字符串是一种非常重要的数据类型&#xff0c;常常用于存储文本数据、处理文件内容以及进行各种文本处理操作。本文将介绍Python中字符串的常用操作&#xff0c;包括字符串的创建、连接、切片、查找、替换等操作&#xff0c;希望能够帮助读者更好地理…

探索ESP32 C++ OOP开发:与传统面向过程编程的比较

探索ESP32 OOP开发&#xff1a;与传统面向过程编程的比较 在嵌入式系统开发中&#xff0c;ESP32是一个强大的平台&#xff0c;可以应用于各种项目和应用场景。在编写ESP32代码时&#xff0c;我们可以选择使用面向对象编程&#xff08;OOP&#xff09;的方法&#xff0c;将代码…

学术交流、论文检索;2024年土木工程与城市建设国际会议(ICCEUC 2024)

2024年土木工程与城市建设国际会议(ICCEUC 2024) 2024 International Conference on Civil Engineering and Urban Construction(ICCEUC 2024) 数据库&#xff1a;EI,CPCI,CNKI,Google Scholar等检索 一、【会议简介】 2024年土木工程与城市建设国际会议(ICCEUC 2024)将在上海盛…