第七题 | 第八题 |
---|---|
![]() |
![]() |
最近在着手开发我的 《匠心星问》 ,它定位是一款 题库 应用,将集题目浏览、发布、解答、做题为一体。打算第一步先以 Flutter 为核心,准备题库资源。于是诞生《每日一题》 系列,准备精心设计一些 Flutter 的问题与解答,作为题库的养料。
第七题:
说说 State 状态类对象创建的时机
在 Flutter 框架中,statefulwidget 对界面交互起到至关重要的作用。而组件类本身只携带组件的配置数据。 状态数据的维护和界面的构建由对应的 State 类完成。理解State状态类,是认识Flutter的关键一。本题将探讨 State 状态类对象实例化的时机。
- | - |
---|---|
![]() |
![]() |
1. 状态对象的诞生地 createState
从我们的老朋友 ChangeableCounter
组件来说,可以看出 StatefulWidget
的派生类,需要实现 createState
方法返回 State
对象。

dart
class ChangeableCounter extends StatefulWidget {
final Color color;
const ChangeableCounter({super.key, required this.color});
@override
State createState() => _ChangeableCounterState(); //<--- 创建 State 对象
}
略...
所以这道题的答案很简单:
StatefulWidget
对应的 State 对象,在createState
回调中被创建。
2. createState 回调是如何触发的
有求知欲的小伙伴可能会想知道:
StatefulWidget 派生类中的
createState
回调函数,是在什么时候被调用的呢?
开发者在代码中并没有调用过 createState
方法,所以这个方法是在 Flutter 框架层
被调用的。了解该函数触发的时机,对初步窥探 Flutter 框架的运行逻辑有很好的价值:
想要知道每个函数什么时候触发,其实非常简单。通过 断点调试 就可以很轻松的看到方法被调用时的堆栈信息。这也是分析源码的重要手段之一。
如下所示,为了看出 _ChangeableCounterState
对象创建时机,可以在改类中放一个构造函数,然后通过断点调试,查看构造函数的调用栈,图中可以看出 _ChangeableCounterState
对象的创建,确实是 ChangeableCounter#createState
方法触发的:

3. 元素与状态类
可以在下方的方法栈中,继续看 createState
的触发场合。如下所示:StatefulElememt
元素在实例化时,会触发 widget.createState
创建状态对象。该状态对象将作为 _state
成员被 StatefulElememt
对象持有:

感兴趣的朋友可以继续向下追踪,StatefulElememt
对象时合时被初始化的。这不是本题的焦点,后面有机会会单独出一题来介绍。
4. 总结
通过本题,从一个简单的 ChangeableCounter
示例出发,深入剖析了 Flutter 中 State
对象的创建过程。了解了以下几个关键点:
createState
方法的职责
每一个 StatefulWidget
都需要通过实现 createState
方法来生成其对应的 State
实例。这一步,是"状态对象"的诞生地。
createState
是何时被调用的?
尽管我们在业务代码中并未手动调用 createState
,但在 Flutter 框架内部,StatefulElement
在构建时会主动触发该方法,并将创建的状态对象与自身绑定。
- 调试是理解框架运行机制的利器
利用断点调试可以直观地观察方法的调用时机和调用栈,为深入理解 Flutter 的构建流程提供了极大的帮助。
通过本题,相信你对 StatefulWidget
和 State
又多了一点点认知。而这只是理解 Flutter 构建机制的一小步,后续我们还将继续探索 Element
、Widget
、State
之间的更多交互细节,敬请期待。
第八题
说说 State 抽象类持有的成员变量
在 Flutter 框架中,statefulwidget 对界面交互起到至关重要的作用。而组件类本身只携带组件的配置数据。 状态数据的维护和界面的构建由对应的 State 类完成。理解 State 状态类,是认识Flutter的关键一。本题将探讨 State 状态类中持有的成员变量。
- | - |
---|---|
![]() |
![]() |
1. State 类中的三个成员
首先从日常的使用来看:
- State 状态类可以访问
widget
来获取配置数据。 - State 状态类可以访问
context
构建上下文获取信息。
所以这两个成员将会被 State 抽象类持有,通过源码可以更清楚的看出。State 中持有 T
类型的 _widget
成员,以及 StatefulElement?
类型的 _element
成员。我们可以发现在 State 中使用的 context,本质上就是 StatefulElement
对象,所以说 Element
其实一直伴随我们左右,并不是什么高不可攀的存在。
dart
T get widget => _widget!;
T? _widget;
BuildContext get context {
return _element!;
}
StatefulElement? _element;

另外,还有一个 _StateLifecycle
类型的成员,用于记录 State 的生命周期,一般在调试环境生效,开发者可无法访问该字段。
2. 详细了解三个成员
_widget
: 组件对象
与状态对象对应的 StatefulWidget
实例, 记当前的 UI 界面配置信息。
成员初始化
:该属性在调用initState
之前由框架初始化。
State 对象在 StatefulElement
实例化时被创建。在构造方法中,还会为 state
的 _widget
成员赋值。这里也就是状态类中 _widget
成员初始化 的场地:

成员的更新
: 调用didUpdateWidget
方法前,该属性将被更新为新组件:
_widget
成员并不是一成不变的,当组件配置信息发生变化,上层节点更新时。下层的 StatefulWidget 对应的状态类并不会重新初始化。而是触发 didUpdateWidget
通知组件对象的变更,在此之前,会将 State._widget
成员更新为新组件:

_element
: 元素对象
BuildContext 的运行时对象,通过构建上下文,可以访问对应组件在树中的信息,得到上层节点存储的共享信息,比如主题、导航、媒体查询等
成员初始化
:该属性在元素实例化后,与状态类绑定
在 StatefulElement
实例化之后,状态类对象会将 _element
赋值为当前的元素对象,从而实现绑定:

成员的更新
: 调用StatefulElement#unmount
取消挂载时,状态类的_element
成员被置空。
总的来看,在 State
状态对象的生命周期内,对应的 BuildContext 是不会发生变化的。

_debugLifecycleState
: 生命周期
_StateLifecycle
枚举有四个成员,默认是 created
:
dart
/// 在启用断言(asserts)时,用于追踪 [State] 对象的生命周期。
enum _StateLifecycle {
/// [State] 对象已被创建,此时会调用 [State.initState] 方法。
created,
/// [State.initState] 方法已被调用,但 [State] 对象尚未准备好进行构建。
/// 此时会调用 [State.didChangeDependencies] 方法。
initialized,
/// [State] 对象已准备好进行构建,且尚未调用 [State.dispose] 方法。
ready,
/// [State.dispose] 方法已被调用,[State] 对象已无法再构建。
defunct,
}
在状态对象生命周期回调的相关时机,会更新到对应的枚举值。比如 initState
之后会更新为 initialized
状态, 在 didChangeDependencies
之后,会更新为 ready
状态:

它们都在 assert
断言中被赋值,所以只在 debug 模式下生效。
3. 总结
从源码层面看,State
类本身其实非常简洁,仅持有必要的对象引用:
_widget
(当前绑定的StatefulWidget
实例)、_element
(对应的StatefulElement
,提供构建上下文)、- 以及
_debugLifecycleState
(仅在调试模式下用于追踪生命周期状态)
State
并不直接持有子组件或 UI 的树形结构,它只是负责维护自身的状态数据,并通过 build()
方法生成组件树来描述 UI 界面。框架会根据是否重建来更新 _widget
并触发 didUpdateWidget
。
如果你有其他的看法,或者有什么想要的题目、或者想提供题目和答案,都欢迎在评论区留言。更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。