鴻蒙開發(fā)頁面和自定義組件生命周期

自定義組件和頁面的關(guān)系:

  • 自定義組件:@Component裝飾的UI單元,可以組合多個系統(tǒng)組件實現(xiàn)UI的復(fù)用,可以調(diào)用組件的生命周期柳恐。
  • 頁面:即應(yīng)用的UI頁面∪柔#可以由一個或者多個自定義組件組成乐设,@Entry裝飾的自定義組件為頁面的入口組件,即頁面的根節(jié)點(diǎn)绎巨,一個頁面有且僅能有一個@Entry近尚。只有被@Entry裝飾的組件才可以調(diào)用頁面的生命周期。

頁面生命周期场勤,即被@Entry裝飾的組件生命周期戈锻,提供以下生命周期接口:

  • onPageShow:頁面每次顯示時觸發(fā)一次,包括路由過程和媳、應(yīng)用進(jìn)入前臺等場景格遭。
  • onPageHide:頁面每次隱藏時觸發(fā)一次,包括路由過程留瞳、應(yīng)用進(jìn)入后臺等場景拒迅。
  • onBackPress:當(dāng)用戶點(diǎn)擊返回按鈕時觸發(fā)。

組件生命周期,即一般用@Component裝飾的自定義組件的生命周期坪它,提供以下生命周期接口:

  • aboutToAppear:組件即將出現(xiàn)時回調(diào)該接口骤竹,具體時機(jī)為在創(chuàng)建自定義組件的新實例后,在執(zhí)行其build()函數(shù)之前執(zhí)行往毡。
  • aboutToDisappear:在自定義組件析構(gòu)銷毀之前執(zhí)行蒙揣。不允許在aboutToDisappear函數(shù)中改變狀態(tài)變量,特別是@Link變量的修改可能會導(dǎo)致應(yīng)用程序行為不穩(wěn)定开瞭。

生命周期流程如下圖所示懒震,下圖展示的是被@Entry裝飾的組件(首頁)生命周期。

image.png

根據(jù)上面的流程圖嗤详,我們從自定義組件的初始創(chuàng)建个扰、重新渲染和刪除來詳細(xì)解釋。

自定義組件的創(chuàng)建和渲染流程

  1. 自定義組件的創(chuàng)建:自定義組件的實例由ArkUI框架創(chuàng)建葱色。
  2. 初始化自定義組件的成員變量:通過本地默認(rèn)值或者構(gòu)造方法傳遞參數(shù)來初始化自定義組件的成員變量递宅,初始化順序為成員變量的定義順序。
  3. 如果開發(fā)者定義了aboutToAppear苍狰,則執(zhí)行aboutToAppear方法办龄。
  4. 在首次渲染的時候,執(zhí)行build方法渲染系統(tǒng)組件淋昭,如果子組件為自定義組件俐填,則創(chuàng)建自定義組件的實例。在執(zhí)行build()函數(shù)的過程中翔忽,框架會觀察每個狀態(tài)變量的讀取狀態(tài)英融,將保存兩個map:
    1. 狀態(tài)變量 -> UI組件(包括ForEach和if)。
    2. UI組件 -> 此組件的更新函數(shù)歇式,即一個lambda方法驶悟,作為build()函數(shù)的子集,創(chuàng)建對應(yīng)的UI組件并執(zhí)行其屬性方法材失,示意如下痕鳍。
build() {
  ...
  this.observeComponentCreation(() => {
    Button.create();
  })

  this.observeComponentCreation(() => {
    Text.create();
  })
  ...
}

當(dāng)應(yīng)用在后臺啟動時,此時應(yīng)用進(jìn)程并沒有銷毀豺憔,所以僅需要執(zhí)行onPageShow额获。

自定義組件重新渲染

當(dāng)事件句柄被觸發(fā)(比如設(shè)置了點(diǎn)擊事件够庙,即觸發(fā)點(diǎn)擊事件)改變了狀態(tài)變量時恭应,或者LocalStorage / AppStorage中的屬性更改,并導(dǎo)致綁定的狀態(tài)變量更改其值時:

  1. 框架觀察到了變化耘眨,將啟動重新渲染昼榛。
  2. 根據(jù)框架持有的兩個map(自定義組件的創(chuàng)建和渲染流程中第4步),框架可以知道該狀態(tài)變量管理了哪些UI組件,以及這些UI組件對應(yīng)的更新函數(shù)胆屿。執(zhí)行這些UI組件的更新函數(shù)奥喻,實現(xiàn)最小化更新。

自定義組件的刪除

如果if組件的分支改變非迹,或者ForEach循環(huán)渲染中數(shù)組的個數(shù)改變环鲤,組件將被刪除:

  1. 在刪除組件之前,將調(diào)用其aboutToDisappear生命周期函數(shù)憎兽,標(biāo)記著該節(jié)點(diǎn)將要被銷毀冷离。ArkUI的節(jié)點(diǎn)刪除機(jī)制是:后端節(jié)點(diǎn)直接從組件樹上摘下,后端節(jié)點(diǎn)被銷毀纯命,對前端節(jié)點(diǎn)解引用西剥,前端節(jié)點(diǎn)已經(jīng)沒有引用時,將被JS虛擬機(jī)垃圾回收亿汞。
  2. 自定義組件和它的變量將被刪除瞭空,如果其有同步的變量,比如@Link疗我、@Prop咆畏、@StorageLink,將從同步源上取消注冊碍粥。

不建議在生命周期aboutToDisappear內(nèi)使用async await鳖眼,如果在生命周期的aboutToDisappear使用異步操作(Promise或者回調(diào)方法),自定義組件將被保留在Promise的閉包中嚼摩,直到回調(diào)方法被執(zhí)行完钦讳,這個行為阻止了自定義組件的垃圾回收。

以下示例展示了生命周期的調(diào)用時機(jī):

// Index.ets
import router from '@ohos.router';

@Entry
@Component
struct MyComponent {
  @State showChild: boolean = true;

  // 只有被@Entry裝飾的組件才可以調(diào)用頁面的生命周期
  onPageShow() {
    console.info('Index onPageShow');
  }
  // 只有被@Entry裝飾的組件才可以調(diào)用頁面的生命周期
  onPageHide() {
    console.info('Index onPageHide');
  }

  // 只有被@Entry裝飾的組件才可以調(diào)用頁面的生命周期
  onBackPress() {
    console.info('Index onBackPress');
  }

  // 組件生命周期
  aboutToAppear() {
    console.info('MyComponent aboutToAppear');
  }

  // 組件生命周期
  aboutToDisappear() {
    console.info('MyComponent aboutToDisappear');
  }

  build() {
    Column() {
      // this.showChild為true枕面,創(chuàng)建Child子組件愿卒,執(zhí)行Child aboutToAppear
      if (this.showChild) {
        Child()
      }
      // this.showChild為false,刪除Child子組件潮秘,執(zhí)行Child aboutToDisappear
      Button('delete Child').onClick(() => {
        this.showChild = false;
      })
      // push到Page2頁面琼开,執(zhí)行onPageHide
      Button('push to next page')
        .onClick(() => {
          router.pushUrl({ url: 'pages/Page2' });
        })
    }

  }
}

@Component
struct Child {
  @State title: string = 'Hello World';
  // 組件生命周期
  aboutToDisappear() {
    console.info('[lifeCycle] Child aboutToDisappear')
  }
  // 組件生命周期
  aboutToAppear() {
    console.info('[lifeCycle] Child aboutToAppear')
  }

  build() {
    Text(this.title).fontSize(50).onClick(() => {
      this.title = 'Hello ArkUI';
    })
  }
}

以上示例中,Index頁面包含兩個自定義組件枕荞,一個是被@Entry裝飾的MyComponent柜候,也是頁面的入口組件,即頁面的根節(jié)點(diǎn)躏精;一個是Child渣刷,是MyComponent的子組件。只有@Entry裝飾的節(jié)點(diǎn)才可以使頁面級別的生命周期方法生效矗烛,所以MyComponent中聲明了當(dāng)前Index頁面的頁面生命周期函數(shù)辅柴。MyComponent和其子組件Child也同時也聲明了組件的生命周期函數(shù)。

  • 應(yīng)用冷啟動的初始化流程為:MyComponent aboutToAppear --> MyComponent build --> Child aboutToAppear --> Child build --> Child build執(zhí)行完畢 --> MyComponent build執(zhí)行完畢 --> Index onPageShow。

  • 點(diǎn)擊“delete Child”碌嘀,if綁定的this.showChild變成false涣旨,刪除Child組件,會執(zhí)行Child aboutToDisappear方法股冗。

  • 點(diǎn)擊“push to next page”霹陡,調(diào)用router.pushUrl接口,跳轉(zhuǎn)到另外一個頁面止状,當(dāng)前Index頁面隱藏穆律,執(zhí)行頁面生命周期Index onPageHide。此處調(diào)用的是router.pushUrl接口导俘,Index頁面被隱藏峦耘,并沒有銷毀,所以只調(diào)用onPageHide旅薄。跳轉(zhuǎn)到新頁面后辅髓,執(zhí)行初始化新頁面的生命周期的流程。

  • 如果調(diào)用的是router.replaceUrl少梁,則當(dāng)前Index頁面被銷毀洛口,執(zhí)行的生命周期流程將變?yōu)椋篒ndex onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。上文已經(jīng)提到凯沪,組件的銷毀是從組件樹上直接摘下子樹第焰,所以先調(diào)用父組件的aboutToDisappear,再調(diào)用子組件的aboutToDisappear妨马,然后執(zhí)行初始化新頁面的生命周期流程挺举。

  • 點(diǎn)擊返回按鈕,觸發(fā)頁面生命周期Index onBackPress烘跺,且觸發(fā)返回一個頁面后會導(dǎo)致當(dāng)前Index頁面被銷毀湘纵。

  • 最小化應(yīng)用或者應(yīng)用進(jìn)入后臺,觸發(fā)Index onPageHide滤淳。當(dāng)前Index頁面沒有被銷毀梧喷,所以并不會執(zhí)行組件的aboutToDisappear。應(yīng)用回到前臺脖咐,執(zhí)行Index onPageShow铺敌。

  • 退出應(yīng)用,執(zhí)行Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear屁擅。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偿凭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子煤蹭,更是在濱河造成了極大的恐慌笔喉,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硝皂,死亡現(xiàn)場離奇詭異常挚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)稽物,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進(jìn)店門奄毡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贝或,你說我怎么就攤上這事吼过。” “怎么了咪奖?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵盗忱,是天一觀的道長。 經(jīng)常有香客問我羊赵,道長趟佃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任昧捷,我火速辦了婚禮闲昭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘靡挥。我一直安慰自己序矩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布跋破。 她就那樣靜靜地躺著簸淀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪毒返。 梳的紋絲不亂的頭發(fā)上啃擦,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機(jī)與錄音饿悬,去河邊找鬼令蛉。 笑死,一個胖子當(dāng)著我的面吹牛狡恬,可吹牛的內(nèi)容都是我干的珠叔。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼弟劲,長吁一口氣:“原來是場噩夢啊……” “哼祷安!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起兔乞,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤汇鞭,失蹤者是張志新(化名)和其女友劉穎凉唐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體霍骄,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡台囱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了读整。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片簿训。...
    茶點(diǎn)故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖米间,靈堂內(nèi)的尸體忽然破棺而出强品,到底是詐尸還是另有隱情,我是刑警寧澤屈糊,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布的榛,位于F島的核電站,受9級特大地震影響逻锐,放射性物質(zhì)發(fā)生泄漏困曙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一谦去、第九天 我趴在偏房一處隱蔽的房頂上張望慷丽。 院中可真熱鬧,春花似錦鳄哭、人聲如沸要糊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锄俄。三九已至,卻和暖如春勺拣,著一層夾襖步出監(jiān)牢的瞬間奶赠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工药有, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毅戈,地道東北人。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓愤惰,卻偏偏與公主長得像苇经,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宦言,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評論 2 350