“心目中的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》
更多关于“心目中的1024程序员节”爱“HarmonyOS 鸿蒙Next”的实战教程也可以访问 https://www.itying.com/category-93-b0.html
请问这个能实现不同用户之间的迁移么?
更多关于“心目中的1024程序员节”爱“HarmonyOS 鸿蒙Next”的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
迁移只能是同一个用户账号之间的行为,
…………一脸懵的近来
哈哈,先定个小目标。
后续慢慢完善
心目中的1024程序员节,是技术创新的盛会。作为程序员,我们热爱“HarmonyOS 鸿蒙Next”,因为它代表了未来操作系统的发展方向。鸿蒙Next不仅在性能上实现了跨越式提升,还通过分布式技术实现了设备间的无缝协同,为开发者提供了更广阔的创新空间。在这个节日里,我们期待与全球开发者一同探索鸿蒙Next的无限可能,推动智能生态的繁荣发展。