flutter Widget的生命周期

做過Android/iOS開發(fā)的都知道我們的頁面都是由生命周期今魔,我們在不同生命周期的回調(diào)方法里會做一些處理。對于flutter而言 一切皆是Widget闪唆,所以了解Widget的生命周期也是必不可少的!
那我們先從簡單的StateLessWidget開始吧钓葫。
下圖是官網(wǎng)對StateLessWidget 生命周期的描述悄蕾,不難看出StateLessWidget只有兩個過程,初始化和build础浮。


StateLessWidget構(gòu)建

StateLessWidget 源碼如下:

abstract class StatelessWidget extends Widget {
  /// Initializes [key] for subclasses.
  const StatelessWidget({ Key key }) : super(key: key);

  /// Creates a [StatelessElement] to manage this widget's location in the tree.
  ///
  /// It is uncommon for subclasses to override this method.
  @override
  StatelessElement createElement() => StatelessElement(this);

  /// Describes the part of the user interface represented by this widget.
  @protected
  Widget build(BuildContext context);
}

StatelessWidget的定義也是很簡單帆调,就三個方法。構(gòu)造方法很好理解豆同,build方法其實就是我們自己實現(xiàn)如何構(gòu)建布局我們的頁面的番刊。createElement我們基本在開發(fā)中不會用到,那它做了些什么呢影锈?以下是StatelessElement的源碼:

class StatelessElement extends ComponentElement {
  /// Creates an element that uses the given widget as its configuration.
  StatelessElement(StatelessWidget widget) : super(widget);

  @override
  StatelessWidget get widget => super.widget as StatelessWidget;

  @override
  Widget build() => widget.build(this);

  @override
  void update(StatelessWidget newWidget) {
    super.update(newWidget);
    assert(widget == newWidget);
    _dirty = true;
    rebuild();
  }
}

在StatelessElement 我們可以到build方法里調(diào)用了widget 的build方法芹务,并且將當(dāng)前element傳到了widget的build方法里,也就對應(yīng)著我們經(jīng)逞纪ⅲ看到的build(BuildContext context)枣抱,其實BuildContext 就是element。upate方法感覺應(yīng)該是更新的時候調(diào)用的辆床。那么到底是在哪調(diào)的呢佳晶,什么時候調(diào)的呢?我們繼續(xù)跟進下ComponentElement的源碼:

class ComponentElement extends Element{

@override
void performRebuild() {
………
Widget build;

build = build();

………
_child = updateChild(_child, build, slot);
…………
}
}

由于代碼篇幅較大讼载,摘出重點轿秧≈械可以看到performRebuild這個方法里調(diào)用了build方法,StatelessElement里的build方法又調(diào)用到了widget里的build方法菇篡。到這 StateLessWidget的聲明周期已經(jīng)完事了漩符。相信你一定有不少疑問,比如 那什么時候顯示驱还,什么時候銷毀陨仅,ComponentElement的performRebuild方法又是什么時候調(diào)用的呢?這里先只做Widget內(nèi)方法調(diào)用順序的分析铝侵,以上問題會在啟動流程部分給出解答灼伤,別著急哈。

StatefulWidget的生命周期

image.png

我們知道StatefulWidget是有狀態(tài)的Widget咪鲜,Widget創(chuàng)建出來之后是不可變狐赡,但是狀態(tài)是可以變的,管理這個狀態(tài)的就是State疟丙,我們可以通過調(diào)用期setState方法去刷新Widget颖侄。先看個我們平時寫StatefulWidget的例子:

class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);

@override
_MyStatefulWidget createState() =>  _MyStatefulWidget();
}


class _MyStatefulWidget extends State<MyStatefulWidget> {

@override
Widget build(BuildContext context){

……………
}

}

我們在State里重寫了build方法,記住這一點喲享郊。跟StateLessWidget一樣我們來看看StatefulWidget的源碼:

class StatefulWidget extends Widget{


const StatefulWidget({Key key}) : super(key: key);

@override
StatefulElement createElement() => StatefulElement(this);


@proteced
State createState();

}

比StateLessWidget多了個createState方法览祖,同樣我們跟進StatefulElement,來探索下createState 是啥時候調(diào)用的炊琉。

class StatefulElement extends ComponentElement{

StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget){

……………
}

……………

@override
void _firstBuild() {
………
final dynamic debugCheckForReturnedFuture = _state.initState();
………

_state.didChangeDependencies();

………

super._firstBuild()
}
……………


}

可以看到createState 在StatefulWidget構(gòu)造的時候就創(chuàng)建了展蒂,同時發(fā)現(xiàn)_firstBuild 好像是第一次創(chuàng)建的意思,我們來看看 這里做了啥苔咪,果然在這里調(diào)用了initState 方法锰悼,之后是didChangeDependencies,那build方法是啥時候調(diào)用的呢团赏?我們看看super._firstBuild()做了什么箕般。

class ComponentElement extends Element{

void _firstBuild() {
rebuild();
}

void rebuild(){
.................
performRebuild();
.......
}

@override
void performRebuild() {
………
Widget build;

build = build();

………
_child = updateChild(_child, build, slot);
…………
}
}

其實這個super._firstBuild()會觸發(fā)rebuild()函數(shù),rebuild()函數(shù)又會觸發(fā)performRebuild(),在performRebuild()函數(shù)里我們看到調(diào)用了build()函數(shù)舔清,至此StatefulWidget的創(chuàng)建過程基本完事丝里。我們可以看到在performRebuild里調(diào)用了updateChild,

 Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
    if (newWidget == null) {
      if (child != null)
        deactivateChild(child);//// widget不活躍
      return null;
    }
    Element newChild;
    if (child != null) {
      bool hasSameSuperclass = true;
      assert(() {
        final int oldElementClass = Element._debugConcreteSubtype(child);
        final int newWidgetClass = Widget._debugConcreteSubtype(newWidget);
        hasSameSuperclass = oldElementClass == newWidgetClass;
        return true;
      }());
      if (hasSameSuperclass && child.widget == newWidget) {
       ..........
      } else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
       ..........
        }());
        newChild = child;
      } else {
        deactivateChild(child);  //// widget不活躍
        assert(child._parent == null);
        newChild = inflateWidget(newWidget, newSlot);
      }
    } else {
    .......
    }

  .............

    return newChild;
  }

在這里會看到deactivateChild体谒,這個方法是將當(dāng)前element標(biāo)注為不活躍杯聚,暫時不會顯示在屏幕上。此時會調(diào)用State的deactivate营密,不能在該方法內(nèi)做銷毀資源操作械媒,因為該element有可能會再次被置為活躍狀態(tài)目锭。當(dāng)我們執(zhí)行了pop评汰,framework會觸發(fā)unmount()函數(shù)纷捞,state dispose會被調(diào)用,我們可以在這個方法里做資源銷毀被去。

image.png

總結(jié)下StatefulWidget生命周期:

  • initState 適合做初始化工作
  • build 避免在build內(nèi)做些邏輯代碼主儡,因為在調(diào)用setState是build方法會重新觸發(fā),容易產(chǎn)生問題
  • dispose 釋放資源惨缆。
image.png

到這里我們就StateLessWidget糜值,StatefulWidget的聲明周期分析完了。本次的分析是基于widget和state內(nèi)方法調(diào)用順序為思路分析的坯墨,對于element內(nèi)的方法調(diào)用順序會在接下來的 flutter app啟動流程里分析寂汇。
歡迎拍磚,交流捣染!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末骄瓣,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子耍攘,更是在濱河造成了極大的恐慌榕栏,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蕾各,死亡現(xiàn)場離奇詭異扒磁,居然都是意外死亡,警方通過查閱死者的電腦和手機式曲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門妨托,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吝羞,你說我怎么就攤上這事始鱼。” “怎么了脆贵?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵医清,是天一觀的道長。 經(jīng)常有香客問我卖氨,道長会烙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任筒捺,我火速辦了婚禮柏腻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘系吭。我一直安慰自己五嫂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沃缘,像睡著了一般躯枢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上槐臀,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天锄蹂,我揣著相機與錄音,去河邊找鬼水慨。 笑死得糜,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的晰洒。 我是一名探鬼主播朝抖,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谍珊!你這毒婦竟也來了槽棍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤抬驴,失蹤者是張志新(化名)和其女友劉穎炼七,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體布持,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡豌拙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了题暖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片按傅。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖胧卤,靈堂內(nèi)的尸體忽然破棺而出唯绍,到底是詐尸還是另有隱情,我是刑警寧澤枝誊,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布况芒,位于F島的核電站,受9級特大地震影響叶撒,放射性物質(zhì)發(fā)生泄漏绝骚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一祠够、第九天 我趴在偏房一處隱蔽的房頂上張望压汪。 院中可真熱鬧,春花似錦古瓤、人聲如沸止剖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽穿香。三九已至亭引,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扔水,已是汗流浹背痛侍。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工朝氓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留魔市,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓赵哲,卻偏偏與公主長得像待德,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子枫夺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容