“心目中的1024程序员节”爱“HarmonyOS 鸿蒙Next”

“心目中的1024程序员节”爱“HarmonyOS 鸿蒙Next” 在前面的文章中(https://developer.huawei.com/consumer/cn/forum/topic/0201628139884080274?fid=0101303901040230869),已经介绍了如何实现跨设备迁移。

本节在上节的基础上,稍作改造,本节演示一个HarmonyOS分布式趣味应用——“心目中的1024程序员节”爱“HarmonyOS”,以实现多设备之间的分布式协同。

参赛主题

#HarmonyOS挑战赛第三期#

【盖楼有奖】福利加“码”:挑战HarmonyOS分布式趣味应用

https://developer.huawei.com/consumer/cn/forum/topic/0202695928837030872?fid=0101303901040230869

选择模板

选择Empty Ablity(Java)

创建项目

创建名为ContinueRemoteFACollaboration的项目作为演示

项目创建完成之后,会自动生成基础的代码结构,接来下直接在该结构上进行微调即可。

MainAbility实现implements IAbilityContinuation接口

MainAbility实现implements IAbilityContinuation接口,代码如下:

package com.waylau.hmos.continueremotefacollaboration;

import com.waylau.hmos.continueremotefacollaboration.slice.MainAbilitySlice;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.IAbilityContinuation;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;
import ohos.security.SystemPermission;
import java.util.ArrayList;
import java.util.List;

/**
* 设备迁移与回迁
*
* @author <a href="https://waylau.com">Way Lau</a>
*/
public class MainAbility extends Ability implements IAbilityContinuation {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(MainAbilitySlice.class.getName());
}

@Override
public boolean onStartContinuation() {
// 重写
return true;
}

@Override
public boolean onSaveData(IntentParams intentParams) {
// 重写
return true;
}

@Override
public boolean onRestoreData(IntentParams intentParams) {
// 重写
return true;
}

@Override
public void onCompleteContinuation(int i) {
}
}

上述代码,重点是重写onStartContinuation、onSaveData、onRestoreData等方法。

申明权限

在项目的对应的config.json中声明跨端迁移访问的权限:ohos.permission.DISTRIBUTED_DATASYNC以及获取分布式设备信息的相关的权限。在config.json中的配置如下:

{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
},
{
"name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
},
{
"name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
},
{
"name": "ohos.permission.GET_BUNDLE_INFO"
}
]
...
}
...
}

同时修改MainAbility,显示申明ohos.permission.DISTRIBUTED_DATASYNC权限,最终,MainAbility完整代码如下:

package com.waylau.hmos.continueremotefacollaboration;

import com.waylau.hmos.continueremotefacollaboration.slice.MainAbilitySlice;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.IAbilityContinuation;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;
import ohos.security.SystemPermission;
import java.util.ArrayList;
import java.util.List;

/**
* 设备迁移与回迁
*
* @author <a href="https://waylau.com">Way Lau</a>
*/
public class MainAbility extends Ability implements IAbilityContinuation {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(MainAbilitySlice.class.getName());
requestPermission();
}

//获取权限
private void requestPermission() {
String[] permission = {
SystemPermission.DISTRIBUTED_DATASYNC
};
List<String> applyPermissions = new ArrayList<>();
for (String element : permission) {
if (verifySelfPermission(element) != 0) {
if (canRequestPermission(element)) {
applyPermissions.add(element);
}
}
}
requestPermissionsFromUser(applyPermissions.toArray(new String[0]), 0);
}

@Override
public boolean onStartContinuation() {
// 重写
return true;
}

@Override
public boolean onSaveData(IntentParams intentParams) {
// 重写
return true;
}

@Override
public boolean onRestoreData(IntentParams intentParams) {
// 重写
return true;
}

@Override
public void onCompleteContinuation(int i) {
}
}

设计界面与布局

修改ability_main.xml布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">

<Image
ohos:id="$+id:imageComponentOne"
ohos:height="237px"
ohos:width="474px"
ohos:image_src="$media:pic"/>

<TextField
ohos:id="$+id:message_textfield"
ohos:height="match_content"
ohos:width="match_parent"
ohos:hint="输入信息"
ohos:top_margin="100vp"
ohos:left_margin="24vp"
ohos:padding="5vp"
ohos:background_element="$graphic:background_ability_main"
ohos:text_alignment="center"
ohos:right_margin="24vp"
ohos:text_size="28vp"/>

<Button
ohos:id="$+id:button_continue_remote_fa"
ohos:height="match_content"
ohos:width="match_content"
ohos:top_margin="8vp"
ohos:background_element="$graphic:background_ability_main"
ohos:layout_alignment="horizontal_center"
ohos:text="迁移"
ohos:text_size="40vp"/>

</DirectionalLayout>

为了应景,在media目录下,我们放置了本期主题的一个素材图片作为背景。

同时,修改background_ability_main.xml样式文件如下:

<?xml version="1.0" encoding="UTF-8" ?>
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:shape="rectangle">
<corners
ohos:radius="10"/>
<solid
ohos:color="#FAEBD7"/>
</shape>

修改MainAbilitySlice

核心的逻辑都集中到了MainAbilitySlice中。MainAbilitySlice同样也要实现implements IAbilityContinuation接口,代码如下:

public class MainAbilitySlice extends AbilitySlice implements IAbilityContinuation {
private static final String TAG = MainAbilitySlice.class.getSimpleName();
private static final HiLogLabel LABEL_LOG =
new HiLogLabel(HiLog.LOG_APP, 0x00001, TAG);

@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
}

@Override
public void onActive() {
super.onActive();
}

@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}

@Override
public boolean onStartContinuation() {
// 重写
return true;
}

@Override
public boolean onSaveData(IntentParams intentParams) {
// 重写
// 保存回迁后恢复状态必须的数据
intentParams.setParam(MESSAGE_KEY, messageTextField.getText());
return true;
}

@Override
public boolean onRestoreData(IntentParams intentParams) {
// 重写
// 传递此前保存的数据
if (intentParams.getParam(MESSAGE_KEY) instanceof String) {
message = (String) intentParams.getParam(MESSAGE_KEY);
isContinued = true;
}
return true;
}

@Override
public void onCompleteContinuation(int i) {
// 终止
terminate();
}
}

上述代码,重点是重写onStartContinuation、onSaveData、onRestoreData、onCompleteContinuation等方法。其中,onSaveData用于保存回迁后恢复状态必须的数据; onRestoreData传递此前保存的数据。onCompleteContinuation方法用于终止Page。

接着为“迁移”“回迁”按钮设置点击事件,代码如下:

private String message;
private boolean isContinued;
private TextField messageTextField;

@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
// 监听跨端迁移FA的事件
Button buttonContinueRemoteFA = (
Button) findComponentById(ResourceTable.Id_button_continue_remote_fa);
buttonContinueRemoteFA.setClickedListener(listener -> continueRemoteFA());
// 设置输入框内容
messageTextField = (TextField) findComponentById(ResourceTable.Id_message_textfield);
if (isContinued && message != null) {
messageTextField.setText(message);
}
}

private void continueRemoteFA() {
HiLog.info(LABEL_LOG, "before startRemoteFA");
String deviceId = DeviceUtils.getDeviceId();
HiLog.info(LABEL_LOG, "get deviceId: %{public}s", deviceId);
if (deviceId != null) {
// 发起迁移流程
// continueAbility()是不可回迁的
// continueAbilityReversibly() 是可以回迁的
continueAbility(deviceId);
}
}

上述代码:

  • 可以通过continueAbility 或者continueAbilityReversibly方法来执行迁移。需要注意是的continueAbility()是不可回迁的,而 continueAbilityReversibly() 是可以回迁的。本例子是使用了continueAbility方法。
  • continueAbility方法可以指定待迁移的设备的ID,该ID通过DeviceUtils工具类获取
  • Message用于表示设备迁移时的状态数据。

DeviceUtils

DeviceUtils代码如下:

package com.waylau.hmos.continueremotefacollaboration;

import ohos.distributedschedule.interwork.DeviceInfo;
import ohos.distributedschedule.interwork.DeviceManager;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import java.util.ArrayList;
import java.util.List;

/**
* 获取当前组网下可迁移的设备id列表
*
* @author <a href="https://waylau.com">Way Lau</a>
*/
public class DeviceUtils {
private static final String TAG = DeviceUtils.class.getSimpleName();
private static final HiLogLabel LABEL_LOG =
new HiLogLabel(HiLog.LOG_APP, 0x00001, TAG);

private DeviceUtils() {}

// 获取当前组网下可迁移的设备id列表
public static List<String> getAvailableDeviceId() {
List<String> deviceIds = new ArrayList<>();
List<DeviceInfo> deviceInfoList =
DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ALL_DEVICE);
if (deviceInfoList == null) {
return deviceIds;
}
if (deviceInfoList.size() == 0) {
HiLog.warn(LABEL_LOG, "did not find other device");
return deviceIds;
}
for (DeviceInfo deviceInfo : deviceInfoList) {
deviceIds.add(deviceInfo.getDeviceId());
}
return deviceIds;
}

// 获取当前组网下可迁移的设备id
// 如果有多个则取第一个
public static String getDeviceId() {
String deviceId = "";
List<String> outerDevices = DeviceUtils.getAvailableDeviceId();
if (outerDevices == null || outerDevices.size() == 0) {
HiLog.warn(LABEL_LOG, "did not find other device");
} else {
for (String item : outerDevices) {
HiLog.info(LABEL_LOG, "outerDevices:%{public}s", item);
}
deviceId = outerDevices.get(0);
}
HiLog.info(LABEL_LOG, "getDeviceId:%{public}s", deviceId);
return deviceId;
}
}

DeviceUtils的getDeviceId方法用于获取在线设备列表。如果有多个,则取任意一个。

运行

多了演示多个设备的迁移情况,需要启动“Super device”,同时启动手机和平台两个模拟器。

将项目同时在这两个模拟器里面运行。

此时,假设手机为设备A,作为源设备,平台为设备B ,作为目标设备。

在设备A上,在输入框中输入一些信息,比如“心目中的1024程序员“

而后点击“迁移”按钮,此时可以看到,Page已经迁移到了设备B上了。说明迁移成功了。

在设备B上可以继续对输入框进行编辑,比如输入“HarmonyOS”

而后点击“迁移”按钮,此时可以看到,Page从设备B迁移到了设备A了。同时,在设备B上输入的内容,也同时迁移到了设备A上,这样就实现了多设备之间的协同。

源码

更多示例源码,见《跟老卫学HarmonyOS》

https://github.com/waylau/harmonyos-tutorial


更多关于“心目中的1024程序员节”爱“HarmonyOS 鸿蒙Next”的实战教程也可以访问 https://www.itying.com/category-93-b0.html

5 回复

请问这个能实现不同用户之间的迁移么?

更多关于“心目中的1024程序员节”爱“HarmonyOS 鸿蒙Next”的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


迁移只能是同一个用户账号之间的行为,

…………一脸懵的近来

哈哈,先定个小目标。

后续慢慢完善

心目中的1024程序员节,是技术创新的盛会。作为程序员,我们热爱“HarmonyOS 鸿蒙Next”,因为它代表了未来操作系统的发展方向。鸿蒙Next不仅在性能上实现了跨越式提升,还通过分布式技术实现了设备间的无缝协同,为开发者提供了更广阔的创新空间。在这个节日里,我们期待与全球开发者一同探索鸿蒙Next的无限可能,推动智能生态的繁荣发展。

回到顶部