Flutter中State深入分析理解

题记
—— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。

**你可能需要
CSDN网易云课堂教程
掘金EDU学院教程
知乎Flutter系列文章

本文将从源码的角度讲述 State 的 四种状态 的变换时机,以及 从 State 的角度来理解 BuildContext 的使用时机


State 有四种状态:

  • created:当State对象被创建时候,State.initState方法会被调用;

  • initialized:当State对象被创建,但还没有准备构建时,State.didChangeDependencies在这个时候会被调用;

  • ready:State对象已经准备好了构建,State.dispose没有被调用的时候;

  • defunct:State.dispose被调用后,State对象不能够被构建。

当一个 Widget 被挂载到 Widgets 树上时,当前的StatefulWidget中通过Widget.createElement方法来创建Element,然后框架层会调用RenderObjectWidget.createRenderObject()来实例化RenderObject,然后Element(就是我们说的BuildContext)关联 Widget 与 RenderObject,这个在 Flutter中Widget 、Element、RenderObject角色深入分析 一节中有描述。

在这里 Element 与Widget 是通过 State来关联的,在 Widget 被挂载到 Widgets 树上时,会通过 StatefulWidget 的createElement 方法来创建一个StatefulElement,源码如下:

///代码清单 1-1 
///StatefulWidget 源码 
abstract class StatefulWidget extends Widget {
  /// Initializes [key] for subclasses.
  const StatefulWidget({ Key key }) : super(key: key);
  @override
  StatefulElement createElement() => StatefulElement(this);

  @protected
  State createState();
}

然后在对应的StatefulElement 中 通过 widget 的 createState 方法来创建一个State,源码如下代码清单 1-2所示 ,在 StatefulElement 使用到的 widget 就是在代码清单 1-1 中所对应的
StatefulWidget。

///代码清单 1-2 
class StatefulElement extends ComponentElement {
  /// Creates an element that uses the given widget as its configuration.
  StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
        super(widget) {
        ... ... 
}

然后此时 State 的状态为 create 状态 ,需要注意的是此时 是在 StatefulElement 的构造函数中执行的,之后会在 StatefulElement 的 _firstBuild 方法中回调 initState方法,而此时State 的状态依然为 create 状态,所以 State是不可用状态,对应的 StatefulElement的(BuildContext)也是不可用状态。

对于 mounted 这个属性,在framework中是直接根据 判断当前 Widget 对应的 Element 是否为空来取值 的,如下所示:

  bool get mounted => _element != null;

StatefulElement 的创建 是在 回调 initState方法 之前,如下代码清单1-3 中所示,StatefulElement 继承于 ComponentElement,在父类 ComponentElement的构造函数中给 变量 _element 赋值, 所以在 实际开发中,在 Widget 的 initState 方法中 获取的 mounted 值为 true , State 对应的状态 为 create , Widget 与 Element 通过 State 挂载 , Element 还不可使用,也就是 context 还不可使用。

///代码清单
class StatefulElement extends ComponentElement {
  /// Creates an element that uses the given widget as its configuration.
  StatefulElement(StatefulWidget widget)
      : _state = widget.createState(),
     ...
    _state._element = this;
    ...
  }

之后 State 的状态 更新 为 initialized 状态,然后回调 didChangeDependencies , initialized 状态 Element 已经将 Widget 与对应 的 RenderObject 关联好, 通过Element 可以获取 RenderObject 中进行测量与计算的一些基本信息,也就是 此时就可以使用 Element (BuildContext)。

initialized 状态 是 Element 在 Widget 与对应 的 RenderObject 形成绑定关系后,还没有里德绘制(build)前的状态,是已准备好的状态 。

之后 State 的状态 更新 为 ready 状态 ,当前(StatefulElement)回调父类(ComponentElement)的 _firstBuild 方法 ,在 ComponentElement 的 _firstBuild 方法中
rebuild ->performRebuild ,对应的RenderObject会被 插到对应的 render树上,然后绘制显示出来。

当 Widget 被 移除时 ,通过 Navigator 的 pop 或者 是在具体的 build 方法中通过变量控制将一个已在页面上渲染显示出来的Widget 移除不显示时,这个 Widget 对应的状态 变为defunct,不可用状态,同时 对应的 Element 与 Widget 、RenderObject 也会解绑,在解绑前会回调这个 Widget 的 didChangeDependencies 方法 ,此时 mounted 值为 true ,因为 对应的 Element 只是准备解绑,还不为null。

当解绑后 回调 dispose ,此时对应的 Element 已被 移除,为null ,所以 此时 被移除的 Widget中的 mounted 值为 false, 当然在这里 context 也是肯定不能使用的。


完毕

公众号 我的大前端生涯

早起的年轻人 CSDN认证博客专家 移动开发 项目管理 Java
只要用心去做,每一件事情还是有可能成功的,当然成功是没有界限的,只不过是达到自己心里的那个目标,公众号:我的大前端生涯,一个爱喝茶的程序员,通常会搞搞SpringBoot 、Herbinate、Mybatiys、Android、iOS、Flutter、Vue、小程序等.
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:设计师小姐姐 返回首页