Stateful组件生命周期
生命周期一:createState
当StatefulWidget组件插入到组件树中时,createState函数由Framework调用,每一个组件都会有一个单独的State,当createState函数执行完毕后,有一个非常重要的属性mounted被Framework设置为true。
class StatefulWidgetDemo extends StatefulWidget {
@override
_StatefulWidgetDemoState createState() => _StatefulWidgetDemoState();
}生命周期二:initState
initState函数在组件被插入树中时被Framework调用(在createState之后)。
此函数只会被调用一次,子类通常会重写此方法,在其中进行初始化操作,比如加载网络数据,重写此方法时一定要调用super.initState(),如下:
@override
void initState() {
super.initState();
//初始化...
}如果此组件需要订阅通知,比如ChangeNotifier或者Stream,则需要在不同的生命周期内正确处理订阅和取消订阅通知。
例如eventbus:
- 在
initState中订阅通知 - 在
didUpdateWidget中,如果需要替换旧组件,则在旧对象中取消订阅,并在新对象中订阅通知 - 并在
dispose中取消订阅
示例一种在initState中的错误写法:
@override
void initState() {
super.initState();
showDialog(context: context, builder: (context) {
return AlertDialog();
});
}异常信息如下:
dependOnInheritedWidgetOfExactType<_LocalizationsScope>() or dependOnInheritedElement() was Called before _StatefulLifecycleState.initState() completed.
解决方案:
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
showDialog(context: context, builder: (context) {
return AlertDialog(title: Text('AlertDialog'),);
});
});
}生命周期三: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的组件属性以引用新的组件,然后使用先前的组件作为参数调用此方法。
@override
void didUpdateWidget(covariant StatefulLifecycle oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget');
}此方法中通常会用当前组件与前组件进行对比。Framework调用完此方法后,会将组件设置为dirty状态,然后调用build 方法,因此无需在此方法中调用setState方法。
生命周期六:deactivate
当框架从树中移除此State时将会调用此方法,在某些情况下,框架将重新插入State到树的其他位置(例如,如果包含该树的子树State从树中的一个位置移植到另一个位置),框架将会调用build方法来提供State适应其在树中的新位置。
生命周期七:dispose
当框架从树中永久移除此State时将会调用此方法,与deactivate的区别是,deactivate还可以重新插入到树中,而dispose表示此State对象永远不会在 build。
其他生命周期
reassemble
当开发过程中进行热重载(hot reload)时,Flutter会调用reassemble方法。通常用于开发调试场景下,刷新资源或重置某些状态。生产环境下不会被调用。dart@override void reassemble() { super.reassemble(); // 热重载时执行的逻辑 }activate
当State被插入到树中的某个位置时(包括初次插入和从其他位置重新插入),会调用activate方法。通常很少需要重写,除非需要在State激活时执行特定逻辑。dart@override void activate() { super.activate(); // State 激活时执行的逻辑 }
几个重要概念
mounted是State中的一个属性,此属性表示当前组件是否在树中,建议在setState前对mounted进行判断dirty表示组件当前的状态为脏状态,下一帧时将会执行build函数,调用setState方法或者或执行didUpdateWidget方法后,组件的状态为dirtyclean与dirty相对应,clean表示组件当前的状态为干净状态,clean状态下组件不会执行build函数
执行次数
build 执行几次
- stl app启动时一次 热重启两次
- stf app启动时一次 热重启两次

