公告

微信

欢迎大家私信交流

Skip to content

Stateful组件生命周期

Stateful组件生命周期

生命周期一:createState

StatefulWidget组件插入到组件树中时,createState函数由Framework调用,每一个组件都会有一个单独的State,当createState函数执行完毕后,有一个非常重要的属性mountedFramework设置为true

dart
class StatefulWidgetDemo extends StatefulWidget {
  @override
  _StatefulWidgetDemoState createState() => _StatefulWidgetDemoState();
}

生命周期二:initState

initState函数在组件被插入树中时被Framework调用(在createState之后)。

此函数只会被调用一次,子类通常会重写此方法,在其中进行初始化操作,比如加载网络数据,重写此方法时一定要调用super.initState(),如下:

dart
@override
void initState() {
  super.initState();
  //初始化...
}

如果此组件需要订阅通知,比如ChangeNotifier或者Stream,则需要在不同的生命周期内正确处理订阅和取消订阅通知。

例如eventbus

  • initState中订阅通知
  • didUpdateWidget中,如果需要替换旧组件,则在旧对象中取消订阅,并在新对象中订阅通知
  • 并在dispose中取消订阅

示例一种在initState中的错误写法:

dart
@override
void initState() {
  super.initState();
  showDialog(context: context, builder: (context) {
    return AlertDialog();
  });
}

异常信息如下:

dependOnInheritedWidgetOfExactType<_LocalizationsScope>() or dependOnInheritedElement() was Called before _StatefulLifecycleState.initState() completed.

解决方案:

dart
@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发生变化时调用此函数,当父组件使用相同的runtimeTypeWidget.key重新构建一个新的组件时,Framework 将更新此State的组件属性以引用新的组件,然后使用先前的组件作为参数调用此方法。

dart
@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 激活时执行的逻辑
    }

几个重要概念

  • mountedState中的一个属性,此属性表示当前组件是否在树中,建议在setState前对mounted进行判断
  • dirty表示组件当前的状态为脏状态,下一帧时将会执行build函数,调用setState方法或者或执行didUpdateWidget方法后,组件的状态为dirty
  • cleandirty相对应,clean表示组件当前的状态为干净状态,clean状态下组件不会执行build函数

执行次数

build 执行几次

  • stl app启动时一次 热重启两次
  • stf app启动时一次 热重启两次

上次更新于: