flutter Widget的生命周期

做过Android/iOS开发的都知道我们的页面都是由生命周期,我们在不同生命周期的回调方法里会做一些处理。对于flutter而言 一切皆是Widget,所以了解Widget的生命周期也是必不可少的!
那我们先从简单的StateLessWidget开始吧。
下图是官网对StateLessWidget 生命周期的描述,不难看出StateLessWidget只有两个过程,初始化和build。


StateLessWidget构建

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的定义也是很简单,就三个方法。构造方法很好理解,build方法其实就是我们自己实现如何构建布局我们的页面的。createElement我们基本在开发中不会用到,那它做了些什么呢?以下是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方法里调用了widget 的build方法,并且将当前element传到了widget的build方法里,也就对应着我们经常看到的build(BuildContext context),其实BuildContext 就是element。upate方法感觉应该是更新的时候调用的。那么到底是在哪调的呢,什么时候调的呢?我们继续跟进下ComponentElement的源码:

class ComponentElement extends Element{

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

build = build();

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

由于代码篇幅较大,摘出重点。可以看到performRebuild这个方法里调用了build方法,StatelessElement里的build方法又调用到了widget里的build方法。到这 StateLessWidget的声明周期已经完事了。相信你一定有不少疑问,比如 那什么时候显示,什么时候销毁,ComponentElement的performRebuild方法又是什么时候调用的呢?这里先只做Widget内方法调用顺序的分析,以上问题会在启动流程部分给出解答,别着急哈。

StatefulWidget的生命周期

image.png

我们知道StatefulWidget是有状态的Widget,Widget创建出来之后是不可变,但是状态是可以变的,管理这个状态的就是State,我们可以通过调用期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 是啥时候调用的。

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构造的时候就创建了,同时发现_firstBuild 好像是第一次创建的意思,我们来看看 这里做了啥,果然在这里调用了initState 方法,之后是didChangeDependencies,那build方法是啥时候调用的呢?我们看看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()会触发rebuild()函数,rebuild()函数又会触发performRebuild(),在performRebuild()函数里我们看到调用了build()函数,至此StatefulWidget的创建过程基本完事。我们可以看到在performRebuild里调用了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,这个方法是将当前element标注为不活跃,暂时不会显示在屏幕上。此时会调用State的deactivate,不能在该方法内做销毁资源操作,因为该element有可能会再次被置为活跃状态。当我们执行了pop,framework会触发unmount()函数,state dispose会被调用,我们可以在这个方法里做资源销毁。

image.png

总结下StatefulWidget生命周期:

  • initState 适合做初始化工作
  • build 避免在build内做些逻辑代码,因为在调用setState是build方法会重新触发,容易产生问题
  • dispose 释放资源。
image.png

到这里我们就StateLessWidget,StatefulWidget的声明周期分析完了。本次的分析是基于widget和state内方法调用顺序为思路分析的,对于element内的方法调用顺序会在接下来的 flutter app启动流程里分析。
欢迎拍砖,交流!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容