Flutter中State深入分析理解

lazihuman
发布于 2020-9-4 17:59
浏览
0收藏

本文将从源代码的角度描述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 也是肯定不能使用的。

作者:早起的年轻人
来源:掘金

分类
已于2020-9-4 17:59:50修改
收藏
回复
举报
回复
    相关推荐