| 第七题 | 第八题 | 
|---|---|
|  |  | 
最近在着手开发我的 《匠心星问》 ,它定位是一款 题库 应用,将集题目浏览、发布、解答、做题为一体。打算第一步先以 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 站 。