Flutter 生命周期研究與應(yīng)用

Flutter 生命周期包括了組件的生命周期以及App的生命周期歉闰。

一蹈集、組件生命周期

一個(gè)flutter組件主要分為無(wú)狀態(tài)組件(StatelessWidget)和有狀態(tài)組件(StatefulWidget)点晴,無(wú)狀態(tài)組件只在創(chuàng)建的時(shí)候渲染一次,創(chuàng)建完成后不能重新渲染,而有狀態(tài)組件可以根據(jù)交互或數(shù)據(jù)變化等,進(jìn)行多次渲染乌奇,本文組件生命周期專(zhuān)指有狀態(tài)組件的生命周期。
組件生命周期主要是:createState眯娱、initState礁苗、didChangeDependencies、reassemble徙缴、didUpdateWidget试伙、build、deactivate娜搂、dispose這幾個(gè)函數(shù),從函數(shù)名我們可以初步感知其作用吱抚,它們大致的流轉(zhuǎn)關(guān)系及作用如圖:


有狀態(tài)組件生命周期簡(jiǎn)圖.png

下面以一個(gè)簡(jiǎn)單的Demo驗(yàn)證這個(gè)流程
1.構(gòu)建一個(gè)簡(jiǎn)單的MyApp:

import 'package:flutter/material.dart';
import 'package:flutterlifecycledemo/ui/home_page.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  /// 初始化state,只會(huì)在第一次構(gòu)建組件時(shí)調(diào)用一次
  ///
  /// 在此期間可以執(zhí)行State各變量的初始賦值
  /// 同時(shí)可以在此處調(diào)用網(wǎng)絡(luò)請(qǐng)求,服務(wù)器返回?cái)?shù)據(jù)后通過(guò)setState刷新頁(yè)面,類(lèi)似于iOS中的ViewDidLoad方法
  @override
  void initState() {
    super.initState();
    print('initState_MyApp');
  }
  /// 該組件所依賴(lài)的State發(fā)生變化時(shí)觸發(fā),或者在initState(組件首次創(chuàng)建)后觸發(fā)
  ///
  /// 該組件所依賴(lài)的State指全局的State,例如語(yǔ)言和主題等
  /// 此方法會(huì)觸發(fā)build
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('didChangeDependencies_MyApp');
  }

  /// 在debug模式下,每次熱重載都會(huì)觸發(fā)該函數(shù)
  ///
  /// 主要是在開(kāi)發(fā)階段在此增加一些debug代碼,檢查代碼問(wèn)題
  @override
  void reassemble() {
    super.reassemble();
    print('reassemble_MyApp');
  }

  /// 組件重新構(gòu)建(如熱重載),父組件發(fā)生build的情況下觸發(fā)
  ///
  /// 注意:
  /// 父組件發(fā)生build,本組件(子組件)該方法才會(huì)被調(diào)用,并且該方法調(diào)用后一定會(huì)再調(diào)用本組件中的build方法
  /// 并且父組件首次創(chuàng)建不會(huì)觸發(fā)
  @override
  void didUpdateWidget(MyApp oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('didUpdateWidget_HomePage');
  }

  /// 組件在被移除節(jié)點(diǎn)后被調(diào)用
  ///
  /// 如果該組件被移除節(jié)點(diǎn),然后未被插入到其他節(jié)點(diǎn)時(shí),則會(huì)繼續(xù)調(diào)用dispose永久移除
  @override
  void deactivate() {
    super.deactivate();
    print('deactivate_MyApp');
  }

  /// 永久移除組件,釋放組件資源
  @override
  void dispose() {
    super.dispose();
    print('dispose_MyApp');
  }

  /// 構(gòu)建需要渲染的widget,會(huì)被多次調(diào)用(會(huì)被setState/didChangeDependencies/didUpdateWidget觸發(fā))
  ///
  /// 只做返回Widget的相關(guān)邏輯
  @override
  Widget build(BuildContext context) {
    print('build_MyApp');
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor: Color(0xff409eff),
        brightness: Brightness.light, // 默認(rèn)狀態(tài)欄顏色
      ),
      home: HomePage(),
    );
  }
}

2.HomPage實(shí)現(xiàn):


import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  HomePage();

  /// 創(chuàng)建state
  ///
  /// 當(dāng)StatefulWidget被調(diào)用時(shí)會(huì)立即執(zhí)行
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool showProgressHud = true;
  double cw = 60;
  /// 模擬加載數(shù)據(jù)
  void loadData(){
    // 5秒后調(diào)用setState
    Future.delayed(Duration(seconds: 5), (){
      setState(() {
        showProgressHud = false;
      });
    });
  }

  /// 初始化state,只會(huì)在第一次構(gòu)建組件時(shí)調(diào)用一次
  ///
  /// 在此期間可以執(zhí)行State各變量的初始賦值
  /// 同時(shí)可以在此處調(diào)用網(wǎng)絡(luò)請(qǐng)求,服務(wù)器返回?cái)?shù)據(jù)后通過(guò)setState刷新頁(yè)面,類(lèi)似于iOS中的ViewDidLoad方法
  @override
  void initState() {
    super.initState();
    print('initState_HomePage');
    loadData();
  }
  /// 該組件所依賴(lài)的State發(fā)生變化時(shí)觸發(fā),或者在initState(組件首次創(chuàng)建)后觸發(fā)
  ///
  /// 該組件所依賴(lài)的State指全局的State,例如語(yǔ)言和主題等
  /// 此方法會(huì)觸發(fā)build
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('didChangeDependencies_HomePage');
  }

  /// 在debug模式下,每次熱重載都會(huì)觸發(fā)該函數(shù)
  ///
  /// 主要是在開(kāi)發(fā)階段在此增加一些debug代碼,檢查代碼問(wèn)題
  @override
  void reassemble() {
    super.reassemble();
    print('reassemble_HomePage');
  }

  /// 組件重新構(gòu)建(如熱重載),父組件發(fā)生build的情況下觸發(fā)
  ///
  /// 注意:
  /// 父組件發(fā)生build,本組件(子組件)該方法才會(huì)被調(diào)用,并且該方法調(diào)用后一定會(huì)再調(diào)用本組件中的build方法
  /// 并且父組件首次創(chuàng)建不會(huì)觸發(fā)
  @override
  void didUpdateWidget(HomePage oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('didUpdateWidget_HomePage');
  }

  /// 組件在被移除節(jié)點(diǎn)后被調(diào)用
  ///
  /// 如果該組件被移除節(jié)點(diǎn),然后未被插入到其他節(jié)點(diǎn)時(shí),則會(huì)繼續(xù)調(diào)用dispose永久移除
  @override
  void deactivate() {
    super.deactivate();
    print('deactivate_HomePage');
  }

  /// 永久移除組件,釋放組件資源
  @override
  void dispose() {
    super.dispose();
    print('dispose_HomePage');
  }

  /// 構(gòu)建需要渲染的widget,會(huì)被多次調(diào)用(會(huì)被setState/didChangeDependencies/didUpdateWidget觸發(fā))
  ///
  /// 只做返回Widget的相關(guān)邏輯
  @override
  Widget build(BuildContext context) {
    print('build_HomePage');
    return Scaffold(
      appBar: AppBar(
        title: Text('Hello Flutter',style: TextStyle(color: Color(0xffffffff),fontSize: 16, fontWeight: FontWeight.bold),),
        centerTitle: true,
        actions: <Widget>[
          FlatButton( // 觸發(fā)setState,showProgressHud=true,當(dāng)前HomeConent組件會(huì)被移除
            child: Text('loadData',style: TextStyle(color:  Color(0xffffffff),fontSize: 14),),
            onPressed: (){
              setState(() {
                showProgressHud = true;
                loadData();
              });
            },
          ),
          FlatButton( // 增加cw值,并只觸發(fā)setState,showProgressHud不變,當(dāng)前SubHomePage組件不會(huì)被移除
            child: Text('click',style: TextStyle(color:  Color(0xffffffff),fontSize: 14),),
            onPressed: (){
              setState(() {
                cw += 10;
              });
            },
          ),
        ],
      ),
      body: Container(
        decoration: BoxDecoration(
          color: Color(0xffffffff),
        ),
        child: Center(
          child: showProgressHud ?
              CircularProgressIndicator() :
              Column(
                mainAxisAlignment: MainAxisAlignment.center ,
                children: <Widget>[
                  Container(width: cw, height: 44,color: Color(0xff889eff),),
                  SubHomePage()
                ],
              )

          ,
        ),
      ),
    );
  }
}

3.SubHomePage實(shí)現(xiàn):


class SubHomePage extends StatefulWidget {
  @override
  _SubHomePageState createState() => _SubHomePageState();
}

class _SubHomePageState extends State<SubHomePage> {

  /// 初始化state,只會(huì)在第一次構(gòu)建組件時(shí)調(diào)用一次
  ///
  /// 在此期間可以執(zhí)行State各變量的初始賦值
  /// 同時(shí)可以在此處調(diào)用網(wǎng)絡(luò)請(qǐng)求,服務(wù)器返回?cái)?shù)據(jù)后通過(guò)setState刷新頁(yè)面,類(lèi)似于iOS中的ViewDidLoad方法
  @override
  void initState() {
    super.initState();
    print('initState_SubHomePage');
  }
  /// 該組件所依賴(lài)的State發(fā)生變化時(shí)觸發(fā),或者在initState(組件首次創(chuàng)建)后觸發(fā)
  ///
  /// 該組件所依賴(lài)的State指全局的State,例如語(yǔ)言和主題等
  /// 子類(lèi)很少重寫(xiě)這個(gè)方法,非必要情況不用重寫(xiě)此方法
  /// 此方法會(huì)觸發(fā)build
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('didChangeDependencies_SubHomePage');
  }

  /// 在debug模式下,每次熱重載都會(huì)觸發(fā)該函數(shù)
  ///
  /// 主要是在開(kāi)發(fā)階段在此增加一些debug代碼,檢查代碼問(wèn)題
  @override
  void reassemble() {
    super.reassemble();
    print('reassemble_SubHomePage');
  }

  /// 組件重新構(gòu)建(如熱重載),父組件發(fā)生build的情況下觸發(fā)
  ///
  /// 注意:
  /// 父組件發(fā)生build,本組件(子組件)該方法才會(huì)被調(diào)用,并且該方法調(diào)用后一定會(huì)再調(diào)用本組件中的build方法
  /// 并且父組件首次創(chuàng)建不會(huì)觸發(fā)
  @override
  void didUpdateWidget(SubHomePage oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('didUpdateWidget_SubHomePage');
  }

  /// 組件在被移除節(jié)點(diǎn)后被調(diào)用
  ///
  /// 如果該組件被移除節(jié)點(diǎn),然后未被插入到其他節(jié)點(diǎn)時(shí),則會(huì)繼續(xù)調(diào)用dispose永久移除
  @override
  void deactivate() {
    super.deactivate();
    print('deactivate_SubHomePage');
  }

  /// 永久移除組件,釋放組件資源
  @override
  void dispose() {
    super.dispose();
    print('dispose_SubHomePage');
  }

  /// 構(gòu)建需要渲染的widget,會(huì)被多次調(diào)用(會(huì)被setState/didChangeDependencies/didUpdateWidget觸發(fā))
  ///
  /// 只做返回Widget的相關(guān)邏輯
  @override
  Widget build(BuildContext context) {
    print('build_SubHomePage');
    return Column(
      children: <Widget>[
        Container(height: 100,),
        Text('Welcome to flutter', style: TextStyle(color: Color(0xff333333), fontSize: 16),),
        Container(
          height: 10,
        ),
        FlatButton(
          onPressed: increaseAction,
          child: Text(
            'Increase',
            style: TextStyle(color: Color(0xffffffff), fontSize: 14),
          ),
          color: Color(0xff409eff),
        )
      ],
    );
  }

  void increaseAction(){
    setState(() {
    });
  }
}

頁(yè)面效果:


IMG_1001CAC5603D-1.jpeg

首次加載控制臺(tái)輸出:


截屏2020-06-28 上午3.13.33.png

正好驗(yàn)證了首次加載有狀態(tài)組件的生命周期百宇,其中build_HomePage打印了兩次,是因?yàn)镠omePage在initState的時(shí)候調(diào)用了模擬網(wǎng)絡(luò)請(qǐng)求方法loadData,在請(qǐng)求完畢后調(diào)用了setState,從而觸發(fā)了HomePage的build秘豹。
接著點(diǎn)擊導(dǎo)航欄上的loadData(屬于HomePage的組件)按鈕携御,觸發(fā):

FlatButton( // 觸發(fā)setState,showProgressHud=true,當(dāng)前SubHomePage組件會(huì)被移除
            child: Text('loadData',style: TextStyle(color:  Color(0xffffffff),fontSize: 14),),
            onPressed: (){
              setState(() {
                showProgressHud = true;
                loadData();
              });
            },
          ),

此時(shí)控制臺(tái)輸出:


截屏2020-06-28 上午3.26.36.png

我們發(fā)現(xiàn)首次生成的SubHomePage被移除了,并且loadData完成后生成新的SubHomePage,新的SubHomePage會(huì)接著走新的首次加載流程

child: Center(
          child: showProgressHud ?
              CircularProgressIndicator() :
              Column(
                mainAxisAlignment: MainAxisAlignment.center ,
                children: <Widget>[
                  Container(width: cw, height: 44,color: Color(0xff889eff),),
                  SubHomePage()
                ],
              )

          ,
        ),

此時(shí)我們點(diǎn)HomePage導(dǎo)航欄上的click按鈕 既绕,增加矩形的寬度:

FlatButton( // 增加cw值,并只觸發(fā)setState,showProgressHud不變,當(dāng)前SubHomePage組件不會(huì)被移除
            child: Text('click',style: TextStyle(color:  Color(0xffffffff),fontSize: 14),),
            onPressed: (){
              setState(() {
                cw += 10;
              });
            },
          ),

控制臺(tái)輸出:


截屏2020-06-28 上午3.36.49.png

此時(shí)我們可以看到HomePage的build觸發(fā)了其子組件SubHomePage的didUpdateWidget和build方法啄刹,但是SubHomePage仍然是原來(lái)的SubHomePage,并未重新釋放(如果釋放后重構(gòu)會(huì)調(diào)用dispose和initState),只是重新build了一次凄贩。
點(diǎn)擊SubHomePage上的increase,控制臺(tái)輸出:


截屏2020-06-28 上午3.42.26.png

cmd+\ 熱重載誓军,控制臺(tái)輸出:
截屏2020-06-28 下午12.21.37.png
二、App生命周期

app生命周期比較簡(jiǎn)單,具體可以參考官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疲扎,一起剝皮案震驚了整個(gè)濱河市昵时,隨后出現(xiàn)的幾起案子捷雕,更是在濱河造成了極大的恐慌,老刑警劉巖壹甥,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件救巷,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡句柠,警方通過(guò)查閱死者的電腦和手機(jī)浦译,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)溯职,“玉大人精盅,你說(shuō)我怎么就攤上這事「组” “怎么了渤弛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)甚带。 經(jīng)常有香客問(wèn)我她肯,道長(zhǎng),這世上最難降的妖魔是什么鹰贵? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任晴氨,我火速辦了婚禮,結(jié)果婚禮上碉输,老公的妹妹穿的比我還像新娘籽前。我一直安慰自己,他們只是感情好敷钾,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布枝哄。 她就那樣靜靜地躺著,像睡著了一般阻荒。 火紅的嫁衣襯著肌膚如雪挠锥。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天侨赡,我揣著相機(jī)與錄音蓖租,去河邊找鬼。 笑死羊壹,一個(gè)胖子當(dāng)著我的面吹牛蓖宦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播油猫,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼稠茂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了情妖?” 一聲冷哼從身側(cè)響起主慰,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嚣州,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后共螺,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體该肴,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年藐不,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了匀哄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡雏蛮,死狀恐怖涎嚼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挑秉,我是刑警寧澤法梯,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站犀概,受9級(jí)特大地震影響立哑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜姻灶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一铛绰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧产喉,春花似錦捂掰、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至塞俱,卻和暖如春姐帚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背敛腌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工卧土, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惫皱,地道東北人像樊。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像旅敷,于是被迫代替她去往敵國(guó)和親生棍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348