StatefulWidget 创建流程详解

2024-04-02  本文已影响0人  晨曦中的花豹

首先需要说明的是,在阅读下面内容之前,需要有一定的widget,element,renderObjetc树的理解

StatefulWidget

其实就widget本身而言,StatefulWidgetStatelessWidget并没有太大的区别,都是描述文件,不存在状态变不变的概念,或者说都是一次性的状态,内部的属性定义最好都是用final来修饰,但是我们在开发中常常用来区分有状态和无状态,实际本质依赖的是widget后面的element,比如StatefulWidget之所以可以保留状态,是因为他的elementStatefulElement没有改变,导致element的一个属性state没有改变,间接的可以理解为element本身绑定了状态,StatelessWidget没有状态是因为他的elementStatelessElement没有绑定状态
简单的理解过后,我们来梳理一下StatefulWidget完整的初始化流程(包括他的element以及state)

flutter页面的刷新依赖于系统的vsync回调,在这个回调中,会进行rebuild,下面是rebuild中的重要的函数

1. updateChild

这个方法中做了很多事情,针对这里说的问题,我只拿出一个点就是,通过widget创建element

Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
  final Element newChild;
  newChild = inflateWidget(newWidget, newSlot);
  return newChild;
}

2. inflateWidget

还是拿重点,这一步创建了Element,并且调用了element 的 mount方法

Element inflateWidget(Widget newWidget, Object? newSlot) {
  final Element newChild = newWidget.createElement();
  newChild.mount(this, newSlot);
  return newChild;
}

3. createElement

StatefulWidget中创建的是StatefulElement,在StatefulElement构造函数中,又通过widget的createState方法创建了state,并且将widget赋值了给state._widget

StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
        super(widget) {
    state._element = this;
    state._widget = widget;
  }

4. mount

StatefulElement没有实现,所以走的他的父类ComponentElement,里边调用了_firstBuild

@override
  void mount(Element? parent, Object? newSlot) {
    super.mount(parent, newSlot);
    assert(_child == null);
    assert(_lifecycleState == _ElementLifecycle.active);
    _firstBuild();
    assert(_child != null);
  }

5. _firstBuild

可以看到面试中长问的一个问题didChangeDependencies什么时候会调用,这里可以明确的知道在element被创建的时候,或者说是state初始化后

void _firstBuild() {
    state.didChangeDependencies();
    super._firstBuild();
  }

这里会调用父类的_firstBuild,而父类只是调用了一下rebuild,而rebuild也仅是做了一件事,调用performRebuild,因为rebuild是定义在Element中的,他只是用来做一些断言判断的,所以具体的如何rebuild是下放到子类去完成的

6. performRebuild(StatefulElement)

@override
  void performRebuild() {
    if (_didChangeDependencies) {
      state.didChangeDependencies();
      _didChangeDependencies = false;
    }
    super.performRebuild();
  }

这里再次出现didChangeDependencies,但是在初始化的时候_didChangeDependenciesfalse,所以state.didChangeDependencies()不会调用重复,这里又引出了didChangeDependencies被调用的另一种情况,就是在rebuild的时候,发现_didChangeDependencies为true,就调用,而_didChangeDependencies的修改是在InheritedWidget通知监听组件时候设置的(更具体的内容请看我之前的文章InheritedWidget 详细理解)

7. performRebuild(ComponentElement)

void performRebuild() {
  Widget? built;
  built = build();
  super.performRebuild();
  _child = updateChild(_child, built, slot);
}

这里边执行了build(),在StatefulElement的实现是Widget build() => state.build(this);,所以最终调用的就是我们在state中经常要写的build函数,super.performRebuild()只是将自己设置为_dirty = false,表示下一帧不需要rebuild我
_child = updateChild(_child, built, slot)就是在build执行完之后,有了新的子widget,再根据子widget重复上述步骤来创建子Element

上一篇下一篇

猜你喜欢

热点阅读