在開始之前,我們先明確自定義元件和頁面的關係:
- 自定義元件:@Component裝飾的UI單元,可以組合多個系統元件實現UI的複用,可以呼叫元件的生命週期。
- 頁面:即應用的UI頁面。可以由一個或者多個自定義元件組成,@Entry裝飾的自定義元件為頁面的入口元件,即頁面的根節點,一個頁面有且僅能有一個@Entry。只有被@Entry裝飾的元件才可以呼叫頁面的生命週期。
頁面生命週期,即被@Entry裝飾的元件生命週期,提供以下生命週期介面:
- onPageShow:頁面每次顯示時觸發一次,包括路由過程、應用進入前臺等場景。
- onPageHide:頁面每次隱藏時觸發一次,包括路由過程、應用進入後臺等場景。
- onBackPress:當使用者點選返回按鈕時觸發。
元件生命週期,即一般用@Component裝飾的自定義元件的生命週期,提供以下生命週期介面:
- aboutToAppear:元件即將出現時回撥該介面,具體時機為在建立自定義元件的新例項後,在執行其build()函式之前執行。
- onDidBuild:元件build()函式執行完成之後回撥該介面,不建議在onDidBuild函式中更改狀態變數、使用animateTo等功能,這可能會導致不穩定的UI表現。
- aboutToDisappear:aboutToDisappear函式在自定義元件析構銷燬之前執行。不允許在aboutToDisappear函式中改變狀態變數,特別是@Link變數的修改可能會導致應用程式行為不穩定。
生命週期流程如下圖所示,下圖展示的是被@Entry裝飾的元件(頁面)生命週期。
以下示例展示了生命週期的呼叫時機:
// Index.ets
import { router } from '@kit.ArkUI';
@Entry
@Component
struct MyComponent {
@State showChild: boolean = true;
@State btnColor:string = "#FF007DFF";
// 只有被@Entry裝飾的元件才可以呼叫頁面的生命週期
onPageShow() {
console.info('Index onPageShow');
}
// 只有被@Entry裝飾的元件才可以呼叫頁面的生命週期
onPageHide() {
console.info('Index onPageHide');
}
// 只有被@Entry裝飾的元件才可以呼叫頁面的生命週期
onBackPress() {
console.info('Index onBackPress');
this.btnColor ="#FFEE0606";
return true // 返回true表示頁面自己處理返回邏輯,不進行頁面路由;返回false表示使用預設的路由返回邏輯,不設定返回值按照false處理
}
// 元件生命週期
aboutToAppear() {
console.info('MyComponent aboutToAppear');
}
// 元件生命週期
onDidBuild() {
console.info('MyComponent onDidBuild');
}
// 元件生命週期
aboutToDisappear() {
console.info('MyComponent aboutToDisappear');
}
build() {
Column() {
// this.showChild為true,建立Child子元件,執行Child aboutToAppear
if (this.showChild) {
Child()
}
// this.showChild為false,刪除Child子元件,執行Child aboutToDisappear
Button('delete Child')
.margin(20)
.backgroundColor(this.btnColor)
.onClick(() => {
this.showChild = false;
})
// push到page頁面,執行onPageHide
Button('push to next page')
.onClick(() => {
router.pushUrl({ url: 'pages/page' });
})
}
}
}
@Component
struct Child {
@State title: string = 'Hello World';
// 元件生命週期
aboutToDisappear() {
console.info('[lifeCycle] Child aboutToDisappear');
}
// 元件生命週期
onDidBuild() {
console.info('[lifeCycle] Child onDidBuild');
}
// 元件生命週期
aboutToAppear() {
console.info('[lifeCycle] Child aboutToAppear');
}
build() {
Text(this.title)
.fontSize(50)
.margin(20)
.onClick(() => {
this.title = 'Hello ArkUI';
})
}
}
// page.ets
@Entry
@Component
struct page {
@State textColor: Color = Color.Black;
@State num: number = 0;
onPageShow() {
this.num = 5;
}
onPageHide() {
console.log("page onPageHide");
}
onBackPress() { // 不設定返回值按照false處理
this.textColor = Color.Grey;
this.num = 0;
}
aboutToAppear() {
this.textColor = Color.Blue;
}
build() {
Column() {
Text(`num 的值為:${this.num}`)
.fontSize(30)
.fontWeight(FontWeight.Bold)
.fontColor(this.textColor)
.margin(20)
.onClick(() => {
this.num += 5;
})
}
.width('100%')
}
}
以上示例中,Index頁面包含兩個自定義元件,一個是被@Entry裝飾的MyComponent,也是頁面的入口元件,即頁面的根節點;一個是Child,是MyComponent的子元件。只有@Entry裝飾的節點才可以使頁面級別的生命週期方法生效,因此在MyComponent中宣告當前Index頁面的頁面生命週期函式(onPageShow / onPageHide / onBackPress)。MyComponent和其子元件Child分別宣告瞭各自的元件級別生命週期函式(aboutToAppear / onDidBuild/aboutToDisappear)。
- 應用冷啟動的初始化流程為:MyComponent aboutToAppear --> MyComponent build --> MyComponent onDidBuild--> Child aboutToAppear --> Child build --> Child onDidBuild --> Index onPageShow。
- 點選“delete Child”,if繫結的this.showChild變成false,刪除Child元件,會執行Child aboutToDisappear方法。
- 點選“push to next page”,呼叫router.pushUrl介面,跳轉到另外一個頁面,當前Index頁面隱藏,執行頁面生命週期Index onPageHide。此處呼叫的是router.pushUrl介面,Index頁面被隱藏,並沒有銷燬,所以只呼叫onPageHide。跳轉到新頁面後,執行初始化新頁面的生命週期的流程。
- 如果呼叫的是router.replaceUrl,則當前Index頁面被銷燬,執行的生命週期流程將變為:Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。上文已經提到,元件的銷燬是從元件樹上直接摘下子樹,所以先呼叫父元件的aboutToDisappear,再呼叫子元件的aboutToDisappear,然後執行初始化新頁面的生命週期流程。
- 點選返回按鈕,觸發頁面生命週期Index onBackPress,且觸發返回一個頁面後會導致當前Index頁面被銷燬。
- 最小化應用或者應用進入後臺,觸發Index onPageHide。當前Index頁面沒有被銷燬,所以並不會執行元件的aboutToDisappear。應用回到前臺,執行Index onPageShow。
- 退出應用,執行Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。