# PageAbility页面导航及迁移 ## 介绍 本示例实现了以下几个功能: 1.同一Page Ability内不同Slice导航 2.不同Page间的AbilitySlice导航 3.Page Ability的跨端迁移 ## 搭建环境 安装DevEco Studio,详情请参考[DevEco Studio下载](https://developer.harmonyos.com/cn/develop/deveco-studio)。 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境: 如果可以直接访问Internet,只需进行[下载HarmonyOS SDK](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/environment_config-0000001052902427)操作。 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考[配置开发环境](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/environment_config-0000001052902427)。 ## 代码结构解读 后台逻辑 ```json pageability │ ContinuationAbility.java #迁移Ability 示例 │ FirstAbility.java #同一Page Ability内不同Slice导航 示例 │ MainAbility.java #主Ability │ MyApplication.java #启动入口 │ SecondAbility.java #不同Page间的AbilitySlice导航 示例 │ └─slice ContinuationAbilitySlice.java #迁移Slice FirstAbilityMainSlice.java #FirstAbility的默认Slice FirstAbilitySecondSlice.java #FirstAbility的第二个Slice MainAbilitySlice.java #MainAbility默认Slice SecondAbilityMainSlice.java #SecondAbility的默认Slice SecondAbilitySecondSlice.java #SecondAbility的第二个Slice ``` 页面布局 ```json ├─layout │ continuation_ability.xml #迁移页面布局 │ first_ability_main_slice.xml #FirstAbilityMainSlice的页面布局 │ first_ability_second_slice.xml #FirstAbilitySecondSlice的页面布局 │ main_ability_slice.xml #MainAbilitySlice的页面布局 │ second_ability_main_slice.xml #SecondAbilityMainSlice的页面布局 │ second_ability_second_slice.xml #SecondAbilitySecondSlice的页面布局 ``` ## 页面布局 布局比较简单,我就贴个运行的效果图大家就清楚了  ## 后台逻辑 ### 1.同一Page Ability内不同Slice导航 有两种情况, 第一,需要返回数据就使用presentForResult方法, ```java //监听按钮点击事件 presentButton.setClickedListener( //启动同一Page Ability的其它slice(lambda表达式的写法) component -> presentForResult(new FirstAbilitySecondSlice(), new Intent(),REQUEST_CODE)); /** * 从其它slice返回数据时,回调此函数 * @param requestCode * @param resultIntent */ @Override protected void onResult(int requestCode, Intent resultIntent) { //可以做安全验证 if (requestCode == REQUEST_CODE && resultIntent != null) { //根据key从Intent中获取从其它slice返回的数据并显示 messageText.setText(resultIntent.getStringParam(FirstAbilitySecondSlice.RESULT_KEY)); } } ``` 目标Slice把数据存到Intent中,当执行terminate()方法时,就会执行回调onResult方法 ```java public class FirstAbilitySecondSlice extends AbilitySlice { public static final String RESULT_KEY = "ohos.samples.pageability.data"; @Override protected void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ohos.samples.pageability.ResourceTable.Layout_first_ability_second_slice); initComponents(); //设置返回数据 setResult(); } /** * 存储要传递的数据到Intent */ private void setResult() { Intent intent = new Intent(); intent.setParam(RESULT_KEY, "{name:'zhangsan',age:20}"); //当能力切片调用 terminate() 方法时,将当前方法设置的结果数据传递给调用者。 setResult(intent); } } ``` 第二,不需要返回数据就用present方法就可以了 ```java //监听按钮点击事件 presentButton.setClickedListener( //启动同一Page Ability的其它slice,不需要返回数据 component -> present(new FirstAbilitySecondSlice(), new Intent())); ``` ### 2.不同Page间的AbilitySlice导航,需要借助Operation的设置 也分两种, 第一,导航到目标Ability的默认Slice,不需要指定Operation的Action,或者设置为空 ```java //启动不同Page间的AbilitySlice,默认slice startSecondButton.setClickedListener(this::startSecondAbilitySlice); /** * 导航到Page默认的slice页面 * @param component */ private void startSecondAbilitySlice(Component component) { Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder().withDeviceId("") //空代表默认路由,也就是默认的slice .withAction("") .withBundleName(getBundleName()) .withAbilityName(SecondAbility.class.getName()) .build(); intent.setOperation(operation); //启动 startAbility(intent); } ``` 第二,导航到目标Ability的非默认页,指定Action,需要借助路由实现 ```java //监听事件,启动不同Page间的AbilitySlice,非默认slice presentSecondButton.setClickedListener(this::startAbilitySlice); /** * 如果导航的slice不是Page默认的slice, * 需要根据设置的路由进行导航 * @param component */ private void startAbilitySlice(Component component) { Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder().withDeviceId("") //指定导航路由 .withAction(ACTION) .withBundleName(getBundleName()) .withAbilityName(SecondAbility.class.getName()) .build(); intent.setOperation(operation); //启动 startAbility(intent); } ``` 路由不是随便写的,需要在config.json注册 ,同时,在对应的SecondAbility中设置   ### 3.Page Ability的跨端迁移 **1.config.json 声明多设备协同权限**  **2.ContinuationAbility 请求用户授权**  **3.ContinuationAbility 处理用户接受/拒绝 授权后的回调函数** 需要implements IAbilityContinuation接口,重写onRequestPermissionsFromUserResult方法  **4.ContinuationAbility 处理其它协同函数**  **5.ContinuationAbilitySlice 迁移数据处理** 同样需要implements IAbilityContinuation接口,重新相关方法。 从终端A 迁移到 终端B 的整个过程: A端: 在onStart方法中初始化迁移监听事件,监听事件里调用continueAbility()方法启动迁移, 开始迁移时,回调onStartContinuation方法确认是否迁移,然后回调在onSaveData方法保存迁移数据,返回是否成功, 成功后,向对端发起迁移请求。 B端: 执行回调函数onRestoreData 恢复数据,返回是否成功,通知A端迁移成功 A端: 执行回调函数onCompleteContinuation 迁移完成,关闭当前Slice  ## 归纳总结 ### 1.迁移过程数据的存储和恢复 ```java @Override public boolean onSaveData(IntentParams intentParams) { HiLog.debug(LABEL_LOG, "onSaveData"); //迁移时,设置需要传递的数据 intentParams.setParam(MESSAGE_KEY, messageTextField.getText()); return true; } @Override public boolean onRestoreData(IntentParams intentParams) { HiLog.debug(LABEL_LOG, "onRestoreData"); //验证返回数据类型 if (intentParams.getParam(MESSAGE_KEY) instanceof String) { //获取待恢复的数据 message = (String) intentParams.getParam(MESSAGE_KEY); //恢复成功 isContinued = true; } return true; } ``` ### 2.迁移数据的回显 迁移后往往需要把A端的数据在B端的页面回显,不要在onRestoreData回调中设置,而是把数据赋值给全局变量,然后在onStart方法中进行设置。 ## 效果展示  ## 完整代码 完整代码可以点击下面的原文链接前往下载 原文链接:https://harmonyos.51cto.com/posts/6418#bkwz