Flutter|StateFulWidget
# Stateful组件生命周期
文章学习来自:https://juejin.cn/post/7011023001093144590 (opens new window)
# 生命周期一:createState
当 StatefulWidget 组件插入到组件树中时,createState 函数由 Framework 调用,每一个组件都会有一个单独的State,当createState函数执行完毕后,有一个非常重要的属性 mounted 被 Framework 设置为 true。
class StatefulWidgetDemo extends StatefulWidget {
_StatefulWidgetDemoState createState() => _StatefulWidgetDemoState();
}
2
3
4
# 生命周期二:initState
initState 函数在组件被插入树中时被 Framework 调用(在 createState 之后)。
此函数只会被调用一次,子类通常会重写此方法,在其中进行初始化操作,比如加载网络数据,重写此方法时一定要调用 super.initState(),如下:
void initState() {
super.initState();
//初始化...
}
2
3
4
5
如果此组件需要订阅通知,比如 ChangeNotifier 或者 Stream,则需要在不同的生命周期内正确处理订阅和取消订阅通知。
例如eventbus。
- 在 initState 中订阅通知。
- 在 didUpdateWidget 中,如果需要替换旧组件,则在旧对象中取消订阅,并在新对象中订阅通知。
- 并在 dispose 中取消订阅。 示例一种在initState中的错误写法:
void initState() {
super.initState();
showDialog(context: context, builder: (context) {
return AlertDialog();
});
}
2
3
4
5
6
7
8
异常信息如下:
dependOnInheritedWidgetOfExactType<_LocalizationsScope>() or dependOnInheritedElement() was Called before _StatefulLifecycleState.initState() completed.
解决方案:
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
showDialog(context: context, builder: (context) {
return AlertDialog(title: Text('AlertDialog'),);
});
});
}
2
3
4
5
6
7
8
9
10
# 生命周期三:didChangeDependencies
didChangeDependencies 方法在 initState 之后由 Framework 立即调用。
另外,当此 State 对象的依赖项更改时被调用,比如其所依赖的 InheritedWidget 发生变化时,Framework 会调用此方法通知组件发生变化。
此方法是生命周期中第一个可以使用 BuildContext.dependOnInheritedWidgetOfExactType 的方法,此方法很少会被重写,因为 Framework 会在依赖发生变化时调用 build,需要重写此方法的场景是:依赖发生变化时需要做一些耗时任务,比如网络请求数据。
didChangeDependencies 方法调用后,组件的状态变为 dirty,立即调用 build 方法。
# 生命周期四:build
此方法是我们最熟悉的,在方法中创建各种组件,绘制到屏幕上。 Framework会在多种情况下调用此方法:
- 调用 initState 方法后。
- 调用 didUpdateWidget 方法后。
- 收到对 setState 的调用后。
- 此 State 对象的依存关系发生更改后(例如,依赖的 InheritedWidget 发生了更改)。
- 调用 deactivate 之后,然后将 State 对象重新插入树的另一个位置。此方法可以在每一帧中调用,此方法中应该只包含构建组件的代码,不应该包含其他额外的功能,尤其是耗时任务。
# 生命周期五:didUpdateWidget
当组件的 configuration 发生变化时调用此函数,当父组件使用相同的 runtimeType 和 Widget.key 重新构建一个新的组件时,Framework 将更新此 State 对象的组件属性以引用新的组件,然后使用先前的组件作为参数调用此方法。
void didUpdateWidget(covariant StatefulLifecycle oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget');
}
2
3
4
5
6
此方法中通常会用当前组件与前组件进行对比。Framework调用完此方法后,会将组件设置为dirty状态,然后调用build 方法,因此无需在此方法中调用setState方法。
# 生命周期六:deactivate
当框架从树中移除此 State 对象时将会调用此方法,在某些情况下,框架将重新插入 State 对象到树的其他位置(例如,如果包含该树的子树 State 对象从树中的一个位置移植到另一个位置),框架将会调用 build 方法来提供 State 对象适应其在树中的新位置。
# 生命周期七:dispose
当框架从树中永久移除此 State 对象时将会调用此方法,与 deactivate 的区别是,deactivate 还可以重新插入到树中,而 dispose 表示此 State 对象永远不会在 build。
# 几个重要概念
- mounted 是 State 对象中的一个属性,此属性表示当前组件是否在树中,建议在 setState 前对mounted 进行判断
- dirty 表示组件当前的状态为脏状态,下一帧时将会执行 build 函数,调用 setState 方法或者 执行 didUpdateWidget 方法后,组件的状态为 dirty
- clean 与 dirty 相对应,clean 表示组件当前的状态为干净状态,clean 状态下组件不会执行 build 函数
# 执行次数
build 执行几次
- stl app启动时一次 热重启两次
- stf app启动时一次 热重启两次