學習筆記 | HarmonyOS的頁面間跳轉
前言
大家好,我又回來啦。這一星期的學習時間又到了。那我們在前幾個星期講的都是harmonyOS里的分布式能力,可能學起來會相對較難一點,那我們這一星期就找了個簡單一點的來學,那這就是頁面間的跳轉了。雖然這和分布式能力毫無相關也比較簡單,但也不是說明這就不重要了,在所有的應用中都基本涉及到了這一個能力,把這學好了,也可以為我們后面的應用開發(fā)打下一個非常良好的基礎。
那現(xiàn)在就先開始我們這星期的西之旅吧!
正文
說到頁面跳轉就不得不提到Ability,Ability是應用所具備能力的抽象,一個應用可以具備多種能力(即可以包含多個Ability)。Page Ability可以用于提供與用戶交互的能力,一個Page可以由一個或多個AbilitySlice構成的,那AbilitySlice又是什么呢,AbilitySlice可以用于實現(xiàn)一個頁面的邏輯。
創(chuàng)建工程
還是和往常一樣,創(chuàng)建一個名為MyJump的手機應用。

一個page包含多個AbilitySlice
設置UI界面
在graphic目錄下增加一個background_button的文件,這個文件可以用于我們按鈕的背景的設置。

- <?xml version="1.0" encoding="UTF-8" ?>
- <shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
- ohos:shape="rectangle">
- <solid
- ohos:color="#007DFF"/>
- <corners
- ohos:radius="100"/>
- </shape>
接下來到layout目錄下增加一個名為ability_second的文件。

- <?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">
- <Text
- ohos:height="match_content"
- ohos:width="match_content"
- ohos:id="$+id:text_second"
- ohos:background_element="$graphic:background_ability_main"
- ohos:layout_alignment="horizontal_center"
- ohos:text="This is SecondAbility"
- ohos:text_size="30vp"/>
- <Button
- ohos:height="match_content"
- ohos:width="match_parent"
- ohos:id="$+id:button_second"
- ohos:background_element="$graphic:background_button"
- ohos:text="返回"
- ohos:text_color="#FFFFFF"
- ohos:text_size="19vp"
- ohos:top_padding="8vp"
- ohos:bottom_padding="8vp"
- ohos:top_margin="20vp"/>
- </DirectionalLayout>
跳轉動作的實現(xiàn)
接下來我們就要在Slice目錄下增加一個類,名為SecondAbilitySlice。


- package com.example.myjump.slice;
- import com.example.myjump.ResourceTable;
- import ohos.aafwk.ability.Ability;
- import ohos.aafwk.content.Intent;
- public class SecondAbilitySlice extends AbilitySlice {
- @Override
- protected void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_ability_second);
- }
- @Override
- protected void onActive() {
- super.onActive();
- }
- @Override
- protected void onForeground(Intent intent) {
- super.onForeground(intent);
- }
- }
接下來是MainAbilitySlice里編寫代碼,使得點擊按鈕能跳轉到SecondAbilitySlice。
- Button buttonsecond = (Button)findComponentById(ResourceTable.Id_page1);
- buttonsecond.setClickedListener(new Component.ClickedListener() {
- @Override
- public void onClick(Component component) {
- Intent intent1 = new Intent();
- present(new SecondAbilitySlice(),intent1); //跳轉到其他頁面
- }
- });
那跳轉到了SecondAbilitySlice,總要有一個按鈕可以跳轉回原來的頁面吧,那我們接下來就編寫代碼,使得點擊按鈕可以銷毀當前頁面,返回MainAbilitySlice。
- Button button = (Button)findComponentById(ResourceTable.Id_button_second);
- button.setClickedListener(new Component.ClickedListener() {
- @Override
- public void onClick(Component component) {
- terminate(); //銷毀當前頁面
- }
- });


那有的人就說了,這個頁面的數據也想帶到那個頁面應該怎么辦呢。沒事不慌,問題不大。接下來我們就來解決攜帶數據的問題。
我們可以在跳轉動作執(zhí)行之前,將數據以鍵值對的形式儲存到網絡中(intent),讓其帶到另外一個頁面。
- intent1.setParam("key","the ability is same!"); //將數據儲存到intent中,讓其以形參的形式傳到另外一個頁面
然后在SecondAbilitySlice中先定義一個輸出控制臺,用于輸出intent中攜帶的數據,然后在onStart里輸出對應的數據。
- HiLog.info(TAG, intent.getStringParam("key")); //用于輸出intent中攜帶的key對應的數據
那怎么將銷毀的頁面的數據往回帶呢,是不是還是用相同的方法呢。那方法也挺相識的,也是將數據寫到intent中,然后調用setResult函數,然后將intent傳到該函數里面。在點擊函數里的代碼如下:
- Intent intent1 = new Intent();
- intent1.setParam("second","我是SecondAbility!");
- setResult(intent1);
- terminate(); //銷毀當前頁面
那這個setResult()函數有什么用呢,這個函數調用之后呢,在MainAbilitySlice里就會調用onResult()函數,同時我們應該將頁面跳轉所用到的present()函數改為presentForResult()函數,在這個函數里面多了一個請求碼的參數,請求碼是用于標識某一個請求的,也就是用來區(qū)分是哪個頁面銷毀頁面之后返回的,請求碼是一個非負的整數,我們就定義請求碼為0,然后調用presentForResult函數。
- presentForResult(new SecondAbilitySlice(),intent1, request_code); //跳轉到其他頁面
在onResult()函數中,會傳來兩個參數,一個就是網絡resultIntent,另外一個就是請求碼requestCode,這個請求碼就是用來區(qū)分是哪個頁面銷毀之后返回來的。例如我們剛剛在用presentForResult跳轉到SecondAbilitySlice時用的請求碼就為0,那從SecondAbilitySlice返回的請求碼就是0。那onResult怎么重寫呢,代碼如下:
- @Override
- protected void onResult(int requestCode, Intent resultIntent) {
- super.onResult(requestCode, resultIntent);
- //這個requestCode可以用來區(qū)分是哪個頁面返回的數據,我們剛剛傳遞的請求碼為0,那從SecondAbilitySlice返回的請求碼就為0
- if(resultIntent != null && requestCode == request_code) {
- HiLog.info(TAG, resultIntent.getStringParam("second"));
- }
- }
那再次運行程序,和剛剛程序的區(qū)別就是在輸出臺會輸出下面兩句話:

第一句話是在MainAbilitySlice點擊按鈕跳轉到SecondAbilitySlice時,在SecondAbilitySlice輸出的,另外一句是在SecondAbilitySlice點擊返回,在MainAbilitySlice輸出的。
一個page包含一個AbilitySlice
在com.example.myjump目錄下新建一個page ability,命名為ThirdAbility。

在ability_third設置界面
- <?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">
- <Text
- ohos:height="match_content"
- ohos:width="match_content"
- ohos:id="$+id:text_third"
- ohos:background_element="$graphic:background_ability_third"
- ohos:layout_alignment="horizontal_center"
- ohos:text="This is ThirdAbility"
- ohos:text_size="30vp"/>
- <Button
- ohos:height="match_content"
- ohos:width="match_parent"
- ohos:id="$+id:button_third"
- ohos:background_element="$graphic:background_button"
- ohos:text="返回"
- ohos:text_color="#FFFFFF"
- ohos:text_size="19vp"
- ohos:top_padding="8vp"
- ohos:bottom_padding="8vp"
- ohos:top_margin="20vp"/>
- </DirectionalLayout>
編寫跳轉動作
在MainAbilitySlice編寫代碼,完成點擊按鈕跳轉到ThirdAbilitySlice去。
先構建一個Intent.OperationBuilder實例,然后鏈式調用withDeviceId、withBundleName、withAbilityName、build。
- Button buttonthird = (Button)findComponentById(ResourceTable.Id_page2);
- buttonthird.setClickedListener(new Component.ClickedListener() {
- @Override
- public void onClick(Component component) {
- Intent intent1 = new Intent();
- Operation operation = new Intent.OperationBuilder() //構建一個Intent.OperationBuilder實例
- .withDeviceId("")
- .withBundleName(getBundleName())
- .withAbilityName(ThirdAbility.class.getName())
- .build();
- intent1.setOperation(operation);
- startAbility(intent1);
- }
- });
那同樣的,我們還需要在ThirdAbilitySlice中編寫代碼,完成點擊返回按鈕銷毀當前頁面,銷毀ThirdAbilitySlice,回到MainAbilitySlice。那有人就覺得用剛才那個terminate函數不就行了嗎,那這就大錯特錯了,在一個Ability下的不同AbilitySlice就是這樣子銷毀頁面的,但在不同的Ability下的話,需要調用terminateAbility函數,那我們就在點擊事件中去調用這個函數。
- Button button = (Button)findComponentById(ResourceTable.Id_button_third);
- button.setClickedListener(new Component.ClickedListener() {
- @Override
- public void onClick(Component component) {
- terminateAbility();
- }
- });
運行一下查看結果。


解決攜帶數據的問題
首先怎么把MainAbilitySlice的數據帶到ThirdAbilitySlice呢,還是和剛剛是相同的,把數據以鍵值對的形式寫到intent中,而且還是用相同的方法setParam。
- intent1.setParam("key","the ability is different!");
接下來還是相同的,在ThirdAbilitySlice里面定義一個輸出控制臺,然后把intent攜帶的數據在onStart輸出出來。
相似的,我們接下來還是實現(xiàn)怎么銷毀頁面之后把數據也帶到MainAbility。那我們還是仍然把數據寫到intent中,然后調用getAbility().setResult(),這個函數里面有兩個參數,第二個就是那個intent,第一個是一個響應碼,這個響應碼是用于標識某一次響應的,作用也和剛剛的標識碼是相識的。這里我們就定義一個響應碼為1,然后調用該函數。最后調用terminAbility函數來實現(xiàn)頁面的銷毀。
- HiLog.info(TAG, intent.getStringParam("key")); //用于輸出intent中攜帶的key對應的數據
- Button button = (Button)findComponentById(ResourceTable.Id_button_third);
- button.setClickedListener(new Component.ClickedListener() {
- @Override
- public void onClick(Component component) {
- Intent intent1 = new Intent();
- intent1.setParam("third","我是從ThirdAbility來的!");
- getAbility().setResult(resultCode, intent1);
- terminateAbility();
- }
- });
這樣子我們就完成了頁面的銷毀工作了,下面我們需要在MainAbilitySlice來接受頁面銷毀后帶來的數據。同樣的還是把startAbility()改為startAbilityForResult(),然后在參數里面多加一個響應碼。然后再重寫onAbilityResult函數,當頁面銷毀之后,會自動調用該函數,那我們就可以在這個函數里面接收數據了。在該函數中會有三個參數,第一個參數是請求碼,也就是我們最開始在MainAbilitySlice里跳轉到ThirdAbilitySlice時的參數,第二個是一個響應碼,也是我們剛剛在getAbility().setResult()中設置的參數,最后一個就是那個intent了,數據也是在這個里面的。
- @Override
- protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
- super.onAbilityResult(requestCode, resultCode, resultData);
- if (requestCode == request_code && resultCode == result_code && resultData != null) {
- HiLog.info(TAG, resultData.getStringParam("third"));
- }
- }
那就讓我們來看看運行的效果吧!

第一句話是點擊“jump to ThirdAbility”按鈕時跳轉到ThirdAbilitySlice頁面輸出的,另外一句是點擊返回按鈕銷毀頁面回到MainAbilitySlice輸出的。
結語
源碼我會放到附件中的,有需求的可以自行下載自行學習,大家有什么看不懂的地方可以私信問我或者對照源碼進行學習。
https://harmonyos.51cto.com/resource/1251