PageAbility跨設備遷移開發(fā)實戰(zhàn)—問答互動
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
跨設備遷移是指將應用中的Page頁遷移到另一設備中??梢酝綉脭?shù)據(jù),甚至可以在的不同設備間遷移,是HarmonyOS特色之一。于是,我以官方給了分布式郵件系統(tǒng)為例,寫了一個簡單的問答互動應用。用戶在設備A上提問,在設備B上回答,信息通過遷移傳遞,并且能查看問答記錄。
Table of Contents
效果展示

主要功能
實現(xiàn)問答界面,通過發(fā)送按鈕將問題、答題等信息轉(zhuǎn)遞到另一設備上。
實現(xiàn)問題記錄界面,對每個完整的問答進行記錄,方便查看。
設備間的數(shù)據(jù)進行同步,擁有相同的問答記錄。
遷移的主要步驟
- 設備A上的Page請求遷移。
- HarmonyOS處理遷移任務,并回調(diào)設備A上Page的保存數(shù)據(jù)方法,用于保存遷移必須的數(shù)據(jù)。
- HarmonyOS在設備B上啟動同一個Page,并回調(diào)其恢復數(shù)據(jù)方法。
PageAbility實現(xiàn)遷移是需要實現(xiàn)IAbilityContinuation接口的,該接口如下:
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by FernFlower decompiler)
- //
- package ohos.aafwk.ability;
- import ohos.aafwk.content.IntentParams;
- public interface IAbilityContinuation {
- int ERR_ABILITY_QUERY_FAILED = -2;
- int ERR_CONTINUE_TIMEOUT = -8;
- int ERR_DEVICE_OFFLINE = -9;
- int ERR_INSTALL_FREE_NOT_SUPPORTED = -4;
- int ERR_NETWORK_UNAVAILABLE = -3;
- int ERR_PARAMETER_INVALID = -6;
- int ERR_PERMISSION_DENIED = -5;
- int ERR_REMOTE_DEVICE_INCOMPATIBLE = -7;
- int ERR_UNKNOWN = -1;
- int SUCCESS = 0;
- boolean onStartContinuation();
- boolean onSaveData(IntentParams var1);
- boolean onRestoreData(IntentParams var1);
- void onCompleteContinuation(int var1);
- default void onRemoteTerminated() {
- throw new RuntimeException("Stub!");
- }
- default void onFailedContinuation(int errorCode) {
- throw new RuntimeException("Stub!");
- }
- }
除了一些異常碼枚舉外,都是遷移中需要用到的主要接口,onStartContinuation()是遷移開始前的預處理函數(shù),可以在這加一些條件檢測,提示等。但是在開始請求遷移前,需要申請權(quán)限ohos.permission.DISTRIBUTED_DATASYNC。config.json中的配置如下:
config.json
- "reqPermissions": [
- {
- "name": "ohos.permission.DISTRIBUTED_DATASYNC"
- }
- ]
接下來只需要PageAbility實現(xiàn)Ability中的onRequestPermissionsFromUserResult接口,就能在啟用遷移之前完成權(quán)限申請了。
- @Override
- public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
- if (permissions == null || permissions.length == 0 || grantResults == null || grantResults.length == 0) {
- return;
- }
- if (requestCode == 0) {
- if (grantResults[0] == IBundleManager.PERMISSION_DENIED) {
- terminateAbility();
- }
- }
- }
完成權(quán)限申請后,只需要通過事件來觸發(fā)遷移開關就行了??梢酝ㄟ^按鈕的點擊事件的來觸發(fā)遷移開關continueAbility(),如下:
- private void initComponents() {
- questionTextField = (TextField) findComponentById(ResourceTable.Id_question_content);
- answerTextField = (TextField) findComponentById(ResourceTable.Id_answer_content);
- findComponentById(ResourceTable.Id_send_button).setClickedListener(this::migrateAbility);
- findComponentById(ResourceTable.Id_return_button).setClickedListener(component->terminate());
- }
- private void migrateAbility(Component component) {
- String questionSend = questionTextField.getText();
- String answerSend = answerTextField.getText();
- if (questionSend.isEmpty() && answerSend.isEmpty()) {
- new ToastDialog(this).setText("Text can not be null").show();
- return;
- }
- try {
- continueAbility();
- } catch (IllegalStateException illegalStateException) {
- HiLog.error(LABEL_LOG, "%{public}s", "migrateAbility: IllegalStateException");
- }
- }
最重要的兩個接口莫過于onSaveData、onRestoreData了,一個是在遷移的時候,將設備A的需要輸入的數(shù)據(jù)存儲,另一個是在設備B進行遷移時,恢復數(shù)據(jù)。
- @Override
- public boolean onSaveData(IntentParams intentParams) {
- intentParams.setParam(QUESTION_KEY, questionTextField.getText());
- intentParams.setParam(ANSWER_KEY, answerTextField.getText());
- return true;
- }
- @Override
- public boolean onRestoreData(IntentParams intentParams) {
- if (intentParams.getParam(QUESTION_KEY) instanceof String) {
- questionText = (String) intentParams.getParam(QUESTION_KEY);
- }
- if (intentParams.getParam(ANSWER_KEY) instanceof String) {
- answerText = (String) intentParams.getParam(ANSWER_KEY);
- }
- if (!questionText.isEmpty() && ! answerText.isEmpty()) {
- AskRecordSlice.UpdateContent("Q:" + questionText + "\n");
- AskRecordSlice.UpdateContent("A:" + answerText + "\n");
- }
- return true;
- }
其中的IntentParams是遷移的數(shù)據(jù)包,提供了setParam、getParam,來傳輸Key-Value數(shù)據(jù)。
設備B上只要正常運行了onRestoreData后,那就會回調(diào)設備A上的onCompleteContinuation,表示遷移順利完成,否則回調(diào)onFailedContinuation,通過捕捉異常碼可進行異常處理。而我在正常遷移完成后,進行了問答記錄的本地存儲:
- @Override
- public void onCompleteContinuation(int code) {
- questionText = questionTextField.getText();
- answerText = answerTextField.getText();
- if (!questionText.isEmpty() && ! answerText.isEmpty()) {
- AskRecordSlice.UpdateContent("Q:" + questionText + "\n");
- AskRecordSlice.UpdateContent("A:" + answerText + "\n");
- }
- }
具體代碼
由于目錄樹中文件較多,整個工程文件的git路徑為:
https://gitee.com/baboon-chen/harmony-osexample.git
需要特殊注意的點:
- //1 跨不同設備時,需要在配置文件中添加上支持的設備類型 config.json
- "deviceType": [
- "phone",
- "tablet"
- ],
- //2 要實現(xiàn)接口的類有哪些?
- 一個應用可能包含多個Page,都有自己的PageSlice棧。僅需要在支持遷移的Page中通過以下方法實現(xiàn)IAbilityContinuation接口。同時,此Page所包含的所有AbilitySlice也需要實現(xiàn)此接口。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)