Flutter 的生命周期(轉(zhuǎn)載)

一胁附,概述

Flutter 的生命周期分為兩個(gè)部分:

  • Widget 的生命周期
  • App 的生命周期

二酒繁,Widget 的生命周期

Flutter 里的 Widget 分為 StatelessWidget 和 StatefulWidget 兩種,這兩種 Widget 的生命周期是不一樣的控妻,我們接下來(lái)具體來(lái)看州袒。

  • StatelessWidget 的生命周期

StatelessWidget 的生命周期只有一個(gè),就是:

    • build

      build 是用來(lái)創(chuàng)建 Widget 的弓候,但因?yàn)?build 在每次界面刷新的時(shí)候都會(huì)調(diào)用郎哭,所以不要在 build 里寫(xiě)業(yè)務(wù)邏輯,可以把業(yè)務(wù)邏輯寫(xiě)到你的 StatelessWidget 的構(gòu)造函數(shù)里菇存。

      StatelessWidget 的 build 函數(shù)代碼如下:

      class TestWidget extends StatelessWidget{
       @override
       Widget build(BuildContext context) { // TODO: implement build
         print('StatelessWidget build'); return Text('Test');
       }
      }
      
  • StatefulWidget 的生命周期

    • StatefulWidget 的生命周期比較復(fù)雜夸研,依次為:

    • createState
    • initState
    • didChangeDependencies
    • build
    • addPostFrameCallback
    • didUpdateWidget
    • deactivate
    • dispose
    • 生命周期圖


      image
    • 接下來(lái)具體介紹一下各個(gè)生命周期。

      • createState

        createState 是 StatefulWidget 里創(chuàng)建 State 的方法依鸥,當(dāng)要?jiǎng)?chuàng)建新的 StatefulWidget 的時(shí)候亥至,會(huì)立即執(zhí)行 createState,而且只執(zhí)行一次,createState 必須要實(shí)現(xiàn):

       class MyScreen extends StatefulWidget {
          @override
          _MyScreenState createState() => _MyScreenState();
        }</pre>
      
      • initState

        前面的 createState 是在創(chuàng)建 StatefulWidget 的時(shí)候會(huì)調(diào)用抬闯,initState 是 StatefulWidget 創(chuàng)建完后調(diào)用的第一個(gè)方法井辆,而且只執(zhí)行一次关筒,類似于 Android 的 onCreate溶握、iOS 的 viewDidLoad(),所以在這里 View 并沒(méi)有渲染蒸播,但是這時(shí) StatefulWidget 已經(jīng)被加載到渲染樹(shù)里了睡榆,這時(shí) StatefulWidget 的 mount的值會(huì)變?yōu)?true袍榆,直到 dispose調(diào)用的時(shí)候才會(huì)變?yōu)?false胀屿。可以在 initState里做一些初始化的操作包雀。

        在 override initState的時(shí)候必須要調(diào)用 super.initState():

        @override void initState() { super.initState();
         
        }
        
      *   **didChangeDependencies**
      
         當(dāng) StatefulWidget 第一次創(chuàng)建的時(shí)候宿崭,**didChangeDependencies**方法會(huì)在 **initState**方法之后立即調(diào)用,之后當(dāng) StatefulWidget 刷新的時(shí)候才写,就不會(huì)調(diào)用了葡兑,除非你的 StatefulWidget 依賴的 InheritedWidget 發(fā)生變化之后,**didChangeDependencies**才會(huì)調(diào)用赞草,所以 **didChangeDependencies**有可能會(huì)被調(diào)用多次讹堤。
      
         這個(gè)函數(shù)會(huì)緊跟在initState之后調(diào)用,并且可以調(diào)用BuildContext.inheritFromWidgetOfExactType厨疙,那么BuildContext.inheritFromWidgetOfExactType的使用場(chǎng)景是什么呢洲守?最經(jīng)典的應(yīng)用場(chǎng)景是
      
      
    new DefaultTabController(length: 3, child: new TabBar(
         tabs: [ "主頁(yè)","訂單","我的" ]
         .map( (data)=>new Text(data) ).toList(),</pre>
    
         TabBar本來(lái)需要定義一個(gè)TabController,但是在外面套一層DefaultTabController就不需要定義TabContrller了,看下源碼:
    
     ```
        @override void didChangeDependencies() { super.didChangeDependencies();
            _updateTabController();
            _initIndicatorPainter();
         } void _updateTabController() { final TabController newController = widget.controller ?? DefaultTabController.of(context);
           ...
         }</pre>
    
    
        注意到這里DefaultTabController.of(context)
    
        <pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">static TabController of(BuildContext context) { final _TabControllerScope scope = context.inheritFromWidgetOfExactType(_TabControllerScope); return scope?.controller;
        }</pre>
    
        實(shí)際上就是調(diào)用BuildContext.inheritFromWidgetOfExactType,也就說(shuō)在didChangeDependencies中沾凄,可以跨組件拿到數(shù)據(jù)梗醇。
    
    *   **build**
    
        在 StatefulWidget 第一次創(chuàng)建的時(shí)候,**build**方法會(huì)在 **didChangeDependencies**方法之后立即調(diào)用撒蟀,另外一種會(huì)調(diào)用 **build**方法的場(chǎng)景是婴削,每當(dāng) UI 需要重新渲染的時(shí)候(**setState**觸發(fā)),**build**都會(huì)被調(diào)用牙肝,所以 **build**會(huì)被多次調(diào)用唉俗,然后 返回要渲染的 Widget。千萬(wàn)不要在 **build**里做除了創(chuàng)建 Widget 之外的操作配椭,因?yàn)檫@個(gè)會(huì)影響 UI 的渲染效率虫溜。
    
    *   **addPostFrameCallback**
    
        **addPostFrameCallback**是 StatefulWidge 渲染結(jié)束的回調(diào),只會(huì)被調(diào)用一次股缸,之后 StatefulWidget 需要刷新 UI 也不會(huì)被調(diào)用衡楞,**addPostFrameCallback**的使用方法是在 **initState**里添加回調(diào):
    
    
         <pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">import 'package:flutter/scheduler.dart';
         @override void initState() { super.initState();
           SchedulerBinding.instance.addPostFrameCallback((_) => {});
         }</pre>
    
        ```
    
     *   **didUpdateWidget**
    
         祖先節(jié)點(diǎn)rebuild widget時(shí)調(diào)用 .當(dāng)組件的狀態(tài)改變的時(shí)候就會(huì)調(diào)用**didUpdateWidget**.(可能會(huì)調(diào)用多次)
    
         理論上setState的時(shí)候會(huì)調(diào)用,但我實(shí)際操作的時(shí)候發(fā)現(xiàn)只是做setState的操作的時(shí)候沒(méi)有調(diào)用這個(gè)方法敦姻。而在我改變代碼hot reload時(shí)候會(huì)調(diào)用 **didUpdateWidget** 并執(zhí)行 **build…**
    
         實(shí)際上這里flutter框架會(huì)創(chuàng)建一個(gè)**新的Widge**t,綁定**本State**瘾境,并在這個(gè)函數(shù)中傳遞老的Widget歧杏。這個(gè)函數(shù)一般用于比較新、老Widget迷守,看看哪些屬性改變了犬绒,并對(duì)State做一些調(diào)整。
    
         需要注意的是兑凿,涉及到controller的變更凯力,需要在這個(gè)函數(shù)中移除老的**controller**的監(jiān)聽(tīng),并創(chuàng)建新**controller**的監(jiān)聽(tīng)礼华。
    
     *   **deactivate(組件移除時(shí))**
    
         當(dāng)要將 State 對(duì)象從渲染樹(shù)中移除的時(shí)候咐鹤,就會(huì)調(diào)用 **deactivate**生命周期,這標(biāo)志著 StatefulWidget 將要銷毀圣絮,但是有時(shí)候 State 不會(huì)被銷毀祈惶,而是重新插入到渲染樹(shù)種。
    
     *   **dispose(組件移除時(shí))**
    
         當(dāng) View 不需要再顯示扮匠,從渲染樹(shù)中移除的時(shí)候捧请,State 就會(huì)永久的從渲染樹(shù)中移除,就會(huì)調(diào)用 **dispose**生命周期餐禁,這時(shí)候就可以在 **dispose**里做一些取消監(jiān)聽(tīng)血久、動(dòng)畫(huà)的操作,和 **initState**是相反的帮非。
    
    

三氧吐,App 的生命周期

AppLifecycleState 就是 App 的生命周期,有:

  • resumed
  • inactive
  • paused
  • suspending

如果想要知道 Flutter App 的生命周期末盔,例如 Flutter 是在前臺(tái)還是在后臺(tái)筑舅,就需要使用到 WidgetsBindingObserver了,使用方法如下:

  1. State 的類 mix WidgetsBindingObserver:
class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
    
   }
  1. 在 State 的 initState里添加監(jiān)聽(tīng):
  @override void initState(){ super.initState();
       WidgetsBinding.instance.addObserver(this);
     }
  1. 在 State 的 dispose里移除監(jiān)聽(tīng):
 @override void dispose() { // TODO: implement dispose
    super.dispose();
    WidgetsBinding.instance.removeObserver(this);
  }</pre>
  1. 在 State 里 override didChangeAppLifecycleState
...@overridevoid didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); if (state == AppLifecycleState.paused) { // went to Background
 } if (state == AppLifecycleState.resumed) { // came back to Foreground
 }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陨舱,一起剝皮案震驚了整個(gè)濱河市翠拣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌游盲,老刑警劉巖误墓,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異益缎,居然都是意外死亡谜慌,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)莺奔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)欣范,“玉大人,你說(shuō)我怎么就攤上這事∧涨恚” “怎么了妨蛹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)晴竞。 經(jīng)常有香客問(wèn)我蛙卤,道長(zhǎng),這世上最難降的妖魔是什么颓鲜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任表窘,我火速辦了婚禮典予,結(jié)果婚禮上甜滨,老公的妹妹穿的比我還像新娘。我一直安慰自己瘤袖,他們只是感情好衣摩,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著捂敌,像睡著了一般艾扮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上占婉,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天泡嘴,我揣著相機(jī)與錄音,去河邊找鬼逆济。 笑死酌予,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的奖慌。 我是一名探鬼主播抛虫,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼简僧!你這毒婦竟也來(lái)了建椰?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤岛马,失蹤者是張志新(化名)和其女友劉穎棉姐,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體啦逆,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伞矩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蹦浦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扭吁。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出侥袜,到底是詐尸還是另有隱情蝌诡,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布枫吧,位于F島的核電站浦旱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏九杂。R本人自食惡果不足惜颁湖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望例隆。 院中可真熱鬧甥捺,春花似錦、人聲如沸镀层。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)唱逢。三九已至吴侦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間坞古,已是汗流浹背备韧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留痪枫,地道東北人织堂。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像听怕,于是被迫代替她去往敵國(guó)和親捧挺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359