
StatefulWidget的生命周期可以清晰地划分为四个主要阶段。
此阶段是组件生命周期的开始,包含以下两个方法:
createState()这是生命周期的起点。当Flutter 框架要构建一个StatefulWidget时,会立即调用其createState方法来创建与之关联的、管理其状态的对象。这个方法只会被调用一次。
initState()在createState创建了State对象,并且该对象被 插 入到组件树(Widget Tree)中后,initState会被调用。它仅调用一次,是进行一次性初始化操作的理想场所。例如:
初始化变量(如状态数据)。
发起网络请求以获取初始数据。
创建动画控制器(AnimationController)或文本编辑控制(TextEditingController)。
订阅事件或数据流。
重要提示:在initState中无法获取到完整的上下文依赖(如 Theme.of(context)),此类操作应在didChangeDependencies中进行。同时,这里不能调用setState,因为此时组件尚未就绪。
组件初始化完成后,就进入了活跃阶段,开始构建用户界面并响应变化。
didChangeDependencies()该方法在initState之后立即被调用一次。此外,每当当前State对象所依赖的InheritedWidget(例如,应用主题、语言环境等全局数据)发生变化时,此方法也会被再次调用。你可以在这里处理依赖变化后的逻辑,例如,当主题改变时更新颜色。
build(BuildContext context)这是State类中唯一必须实现的方法,也是整个生命周期的核心 。它负责描述如何根据当前状态构建用户界面。在以下情况发生后,build方法 会被调用:
第一次插入组件树时(在initState和didChangeDependencies之后)。
调用了setState方法。
父组件重建,并触发了当前组件的更新。由于此方法 会频繁调用,因此应确保其中的逻辑简洁高效,避免进行耗时操作。
当组件的状态或配置发生变化时,会进入更新阶段。
didUpdateWidget(covariant T oldWidget)当父组件重建并提供了一个类型和键(key)相同但配置不同的新StatefulWidget实例时,该方法 会被调用。参数oldWidget是旧的widget实例,你可以在此比较新旧 widget 的属性差异,并根据需要更新当前状态,甚至调用setState。注意,调用setState触发的更新不会调用此方法。
setState()这是一个非常重要的方法,但它本身并非一个生命周期"回调"。它用于通知 Flutter 框架:“当前组件内部的状态已经改变了,请重新构建 UI”。调用setState后,框架会标记该组件为“脏的”,并在下一帧重新调用其 build方法以更新界面。你应将修改状态变量的操作放在setState的回调函数中。
当组件不再需要时,会进入销毁阶段以释放资源。
deactivate()当State对象对应的组件被从组件树中移除时,会调用此方法 。在某些情况下(例如使用GlobalKey移动组件),组件可能被暂时移除后又重新插入到树的其他位置,此时deactivate会被调用,但后续dispose可能不会立即调用。这里适合做一些临时的清理工作。
dispose()这是生命周期中的最后一个方法。当State对象被永久地从组件树中移除时,dispose会被调用。此方法仅调用一次,你必须在此处进行重要的清理工作,以防止内存泄漏,例如:
取消所有动画控制器(animationController.dispose())。
取消对数据流的订阅(streamSubscription.cancel())。
清理其他所有占用的资源 。
牢记initState和dispose的配对使用:在initState中初始化的资源(如控制器、流订阅),务必在dispose中销毁。
理解setState的用途:它只应用于更新当前组件内部的状态。对于子组件的状态或应用级的复杂状态,应考虑使用更专业的状态管理方案(如Provider、Bloc 等)。
保持build方法轻量:避免在build方法中执行繁重的计算或同步的I/O 操作,以确保UI的流畅性。
善用didUpdateWidget:当组件的状态既依赖于内部变量,又受父组件传入的属性影响时,didUpdateWidget是协调这两者变化的理想位置。