Flutter中State深入分析理解
本文将从源代码的角度描述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 也是肯定不能使用的。
作者:早起的年轻人
来源:掘金