美文网首页
StatefulWidget 创建流程详解

StatefulWidget 创建流程详解

作者: 晨曦中的花豹 | 来源:发表于2024-04-02 12:21 被阅读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

    相关文章

      网友评论

          本文标题:StatefulWidget 创建流程详解

          本文链接:https://www.haomeiwen.com/subject/hfjwtjtx.html