Module類型
Module按照使用場景可以分為兩種類型:
Ability類型的Module:
用于實現應用的功能和特性。每一個Ability類型的Module編譯后,會生成一個以.hap為后綴的文件,我們稱其為HAP(Harmony Ability Package)包。HAP包可以獨立安裝和運行,是應用安裝的基本單位,一個應用中可以包含一個或多個HAP包,具體包含如下兩種類型。
- entry類型的Module:
應用的主模塊,包含應用的入口界面、入口圖標和主功能特性,編譯后生成entry類型的HAP。每一個應用分發到同一類型的設備上的應用程序包,只能包含唯一一個entry類型的HAP,也可以不包含。 - feature類型的Module:
應用的動態特性模塊,編譯后生成feature類型的HAP。一個應用中可以包含一個或多個feature類型的HAP,也可以不包含。
Library類型的Module:
用于實現代碼和資源的共享。同一個Library類型的Module可以被其他的Module多次引用,合理地使用該類型的Module,能夠降低開發和維護成本。Library類型的Module分為Static和Shared兩種類型,編譯后會生成共享包。 - Static Library:靜態共享庫
編譯后會生成一個以.har為后綴的文件,即靜態共享包HAR(Harmony Archive Package)。 - Shared Library:動態共享庫。
編譯后會生成一個以.hsp為后綴的文件,即動態共享包HSP(Harmony Shared Package)。
UIAbility組件
UIAbility組件是一種包含UI的應用組件,主要用于和用戶交互。
UIAbility組件是系統調度的基本單元,為應用提供繪制界面的窗口。
一個應用可以包含一個或多個UIAbility組件。例如,在支付應用中,可以將入口功能和收付款功能分別配置為獨立的UIAbility。
每一個UIAbility組件實例都會在最近任務列表中顯示一個對應的任務
UIAbility組件生命周期
-
Create:
Create狀態為在應用加載過程中,UIAbility實例創建完成時觸發,系統會調用onCreate()回調。可以在該回調中進行頁面初始化操作,例如變量定義資源加載等,用于后續的UI展示。
-
WindowStageCreate:
UIAbility實例創建完成之后,在進入Foreground之前,系統會創建一個WindowStage。WindowStage創建完成后會進入onWindowStageCreate()回調,可以在該回調中設置UI加載、設置WindowStage的事件訂閱。
在onWindowStageCreate()回調中通過loadContent()方法設置應用要加載的頁面,并根據需要調用on('windowStageEvent')方法訂閱WindowStage的事件(獲焦/失焦、切到前臺/切到后臺、前臺可交互/前臺不可交互)。
通過WindowStage對象的loadContent()方法設置啟動頁面。 -
WindowStageWillDestroy
在onWindowStageWillDestroy()中注銷WindowStage事件訂閱(獲焦/失焦、切到前臺/切到后臺、前臺可交互/前臺不可交互)
-
WindowStageDestroy
可以在該回調中釋放UI資源。
-
Foreground和Background狀態
onForeground()回調,在UIAbility的UI可見之前,如UIAbility切換至前臺時觸發。可以在onForeground()回調中申請系統需要的資源,或者重新申請在onBackground()中釋放的資源。
onBackground()回調,在UIAbility的UI完全不可見之后,如UIAbility切換至后臺時候觸發。可以在onBackground()回調中釋放UI不可見時無用的資源,或者在此回調中執行較為耗時的操作,例如狀態保存等。
-
Destroy
Destroy狀態在UIAbility實例銷毀時觸發。可以在onDestroy()回調中進行系統資源的釋放、數據的保存等操作。
UIAbility組件啟動模式
module.json5配置文件中的launchType:singleton/multiton -
singleton啟動模式
singleton啟動模式為單實例模式,也是默認情況下的啟動模式。
每次調用startAbility()方法時,如果應用進程中該類型的UIAbility實例已經存在,則復用系統中的UIAbility實例。系統中只存在唯一一個該UIAbility實例,即在最近任務列表中只存在一個該類型的UIAbility實例。
-
multiton啟動模式
multiton啟動模式為多實例模式,每次調用startAbility()方法時,都會在應用進程中創建一個新的該類型UIAbility實例。即在最近任務列表中可以看到有多個該類型的UIAbility實例。
-
specified啟動模式
specified啟動模式為指定實例模式,針對一些特殊場景使用(例如文檔應用中每次新建文檔希望都能新建一個文檔實例,重復打開一個已保存的文檔希望打開的都是同一個文檔實例)。
UIAbility組件與UI的數據同步
- 使用EventHub進行數據通信:在基類Context中提供了EventHub對象,可以通過發布訂閱方式來實現事件的傳遞。在事件傳遞前,訂閱者需要先進行訂閱,當發布者發布事件時,訂閱者將接收到事件并進行相應處理。
import { hilog } from '@kit.PerformanceAnalysisKit';
import { UIAbility, Context, Want, AbilityConstant } from '@kit.AbilityKit';const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = '[EventAbility]';export default class EntryAbility extends UIAbility {onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {// 獲取eventHublet eventhub = this.context.eventHub;// 執行訂閱操作eventhub.on('event1', this.eventFunc);eventhub.on('event1', (data: string) => {// 觸發事件,完成相應的業務操作});hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onCreate');}// ...eventFunc(argOne: Context, argTwo: Context): void {hilog.info(DOMAIN_NUMBER, TAG, '1. ' + `${argOne}, ${argTwo}`);return;}
}
根據需要調用eventHub.off()方法取消該事件的訂閱。
- 使用AppStorage/LocalStorage進行數據同步:ArkUI提供了AppStorage和LocalStorage兩種應用級別的狀態管理方案,可用于實現應用級別和UIAbility級別的數據同步
UIAbility組件間交互(設備內)
當一個應用內包含多個UIAbility時,存在應用內啟動UIAbility的場景。例如在支付應用中從入口UIAbility啟動收付款UIAbility。
- 在EntryAbility中,通過調用startAbility()方法啟動UIAbility,want為UIAbility實例啟動的入口參數
let wantInfo: Want = {deviceId: '', // deviceId為空表示本設備bundleName: 'com.samples.stagemodelabilitydevelop',moduleName: 'entry', // moduleName非必選abilityName: 'FuncAbilityA',parameters: {// 自定義信息info: '來自EntryAbility Page_UIAbilityComponentsInteractive頁面'},};// context為調用方UIAbility的UIAbilityContextthis.context.startAbility(wantInfo).then(() => {hilog.info(DOMAIN_NUMBER, TAG, 'startAbility success.');}).catch((error: BusinessError) => {hilog.error(DOMAIN_NUMBER, TAG, 'startAbility failed.');});
在一個EntryAbility啟動另外一個FuncAbility時,希望在被啟動的FuncAbility完成相關業務后,能將結果返回給調用方。
調用startAbilityForResult()接口啟動FuncAbility,異步回調中的data用于接收FuncAbility停止自身后返回給EntryAbility的信息。
context.startAbilityForResult(want).then((data) => {if (data?.resultCode === RESULT_CODE) {// 解析被調用方UIAbility返回的信息let info = data.want?.parameters?.info;hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? '');if (info !== null) {promptAction.showToast({message: JSON.stringify(info)});}}hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(data.resultCode) ?? '');
}).catch((err: BusinessError) => {hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
});
- 在FuncAbility的onCreate()或者onNewWant()生命周期回調文件中接收EntryAbility傳遞過來的參數。
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';export default class FuncAbilityA extends UIAbility {onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {// 接收調用方UIAbility傳過來的參數let funcAbilityWant = want;let info = funcAbilityWant?.parameters?.info;}//...
}
- 在FuncAbility業務完成之后,如需要停止當前UIAbility實例,在FuncAbility中通過調用terminateSelf()方法實現。
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';const TAG: string = '[Page_FromStageModel]';
const DOMAIN_NUMBER: number = 0xFF00;@Entry
@Component
struct Page_FromStageModel {build() {Column() {//...Button('FuncAbilityB').onClick(() => {let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext// context為需要停止的UIAbility實例的AbilityContextcontext.terminateSelf((err) => {if (err.code) {hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self. Code is ${err.code}, message is ${err.message}`);return;}});})}//...}
}
在FuncAbility停止自身時,需要調用terminateSelfWithResult()方法,入參abilityResult為FuncAbility需要返回給EntryAbility的信息。
context.terminateSelfWithResult(abilityResult, (err) => {if (err.code) {hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self with result. Code is ${err.code}, message is ${err.message}`);return;}
});
- 如需要關閉應用所有的UIAbility實例,可以調用ApplicationContext的killAllProcesses()方法實現關閉應用所有的進程。
頁面和自定義組件生命周期
頁面生命周期,即被@Entry裝飾的組件生命周期,提供以下生命周期接口:
-
onPageShow:頁面每次顯示時觸發一次,包括路由過程、應用進入前臺等場景。
-
onPageHide:頁面每次隱藏時觸發一次,包括路由過程、應用進入后臺等場景。
-
onBackPress:當用戶點擊返回按鈕時觸發。
組件生命周期,即一般用@Component裝飾的自定義組件的生命周期,提供以下生命周期接口:
- aboutToAppear:組件即將出現時回調該接口,具體時機為在創建自定義組件的新實例后,在執行其build()函數之前執行。
- onDidBuild:組件build()函數執行完成之后回調該接口,開發者可以在這個階段進行埋點數據上報等不影響實際UI的功能。不建議在onDidBuild函數中更改狀態變量、使用animateTo等功能,這可能會導致不穩定的UI表現。
- aboutToDisappear:aboutToDisappear函數在自定義組件析構銷毀之前執行。不允許在aboutToDisappear函數中改變狀態變量,特別是@Link變量的修改可能會導致應用程序行為不穩定
鏈接 - 應用冷啟動的初始化流程為:MyComponent aboutToAppear --> MyComponent build -->
MyComponent onDidBuild–> Child aboutToAppear --> Child build -->
Child onDidBuild --> Index onPageShow。 - 退出應用,執行Index onPageHide --> MyComponent aboutToDisappear --> Child
aboutToDisappear。
NavDestination頁面生命周期
- aboutToAppear:在創建自定義組件后,執行其build()函數之前執行(NavDestination創建之前),允許在該方法中改變狀態變量,更改將在后續執行build()函數中生效。
- onWillAppear:NavDestination創建后,掛載到組件樹之前執行,在該方法中更改狀態變量會在當前幀顯示生效。
- onAppear:通用生命周期事件,NavDestination組件掛載到組件樹時執行。
- onWillShow:NavDestination組件布局顯示之前執行,此時頁面不可見(應用切換到前臺不會觸發)。
- onShown:NavDestination組件布局顯示之后執行,此時頁面已完成布局。
- onWillHide:NavDestination組件觸發隱藏之前執行(應用切換到后臺不會觸發)。
- onHidden:NavDestination組件觸發隱藏后執行(非棧頂頁面push進棧,棧頂頁面pop出棧或應用切換到后臺)。
- onWillDisappear:NavDestination組件即將銷毀之前執行,如果有轉場動畫,會在動畫前觸發(棧頂頁面pop出棧)。
- onDisappear:通用生命周期事件,NavDestination組件從組件樹上卸載銷毀時執行。
- aboutToDisappear:自定義組件析構銷毀之前執行,不允許在該方法中改變狀態變量。
系統路由表
系統路由表不支持預覽器,跨平臺及模擬器。
- 在跳轉目標模塊的配置文件module.json5添加路由表配置:
{"module" : {"routerMap": "$profile:route_map"}}
- 添加完路由配置文件地址后,需要在工程resources/base/profile中創建route_map.json文件。添加如下配置信息:
{"routerMap": [{"name": "PageOne","pageSourceFile": "src/main/ets/pages/PageOne.ets","buildFunction": "PageOneBuilder","data": {"description" : "this is PageOne"}}]}
配置項 | 說明 |
---|---|
name | 跳轉頁面名稱。 |
pageSourceFile | 跳轉目標頁在包內的路徑,相對src目錄的相對路徑。 |
buildFunction | 跳轉目標頁的入口函數名稱,必須以@Builder修飾。 |
data | 應用自定義字段。可以通過配置項讀取接口getConfigInRouteMap獲取。 |
- 在跳轉目標頁面中,需要配置入口Builder函數,函數名稱需要和route_map.json配置文件中的buildFunction保持一致,否則在編譯時會報錯
// 跳轉頁面入口函數@Builderexport function PageOneBuilder() {PageOne()}@Componentstruct PageOne {pathStack: NavPathStack = new NavPathStack()build() {NavDestination() {}.title('PageOne').onReady((context: NavDestinationContext) => {this.pathStack = context.pathStack})}}
- 通過pushPathByName等路由接口進行頁面跳轉。(注意:此時Navigation中可以不用配置navDestination屬性)。
@Entry@Componentstruct Index {pageStack : NavPathStack = new NavPathStack();build() {Navigation(this.pageStack){}.onAppear(() => {this.pageStack.pushPathByName("PageOne", null, false);}).hideNavBar(true)}}