关于flutter:老孟FlutterStateful-组件的生命周期​

34次阅读

共计 4796 个字符,预计需要花费 12 分钟才能阅读完成。

老孟导读 :对于生命周期的文章共有 2 篇,第一篇是介绍 Flutter 中 Stateful 组件的生命周期。
博客地址:http://laomengit.com/blog/20201227/Stateful%E7%BB%84%E4%BB%B6%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.html

第二篇是 Flutter 中与平台相干的生命周期,

博客地址:http://laomengit.com/blog/20201227/%E7%9B%B8%E5%85%B3%E5%B9%B3%E5%8F%B0%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.html

博客中还有更多精彩文章,也欢送退出 Flutter 交换群。

此篇文章介绍 StatefulWidget 组件的生命周期,StatefulWidget 组件的生命周期时十分重要的知识点,就像 Android 中 Activity 的生命周期一样,不仅在当前的工作中常常用到,面试也会常常被问到。

在 Flutter 中所有皆 组件 ,而组件又分为 StatefulWidget(有状态)StatelessWidget(无状态) 组件,他们之间的区别是 StatelessWidget 组件发生变化时必须从新创立新的实例,而 StatefulWidget 组件则能够间接扭转以后组件的状态而无需从新创立新的实例。

留神:应用的 Flutter 版本 和 Dart 版本如下:

Flutter 1.22.4 • channel stable • https://github.com/flutter/fl…
Framework • revision 1aafb3a8b9 (6 weeks ago) • 2020-11-13 09:59:28 -0800
Engine • revision 2c956a31c0
Tools • Dart 2.10.4

不同的版本 StatefulWidget 组件的生命周期会有差别。

上面的 StatefulWidget 和 State 结构图是 StatefulWidget 组件生命周期的概览,不同版本的差别也能够比照此结构图。

生命周期流程图:

上面具体介绍 StatefulWidget 组件的生命周期。

生命周期一:createState

上面是一个非常简单的 StatefulWidget 组件:

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

class _StatefulWidgetDemoState extends State<StatefulWidgetDemo> {
  @override
  Widget build(BuildContext context) {return Container();
  }
}

当咱们构建一个 StatefulWidget 组件时,首先执行其 构造函数(下面的代码没有显示的构造函数,但有默认的无参构造函数),而后执行 createState 函数。但构造函数并不是生命周期的一部分。

当 StatefulWidget 组件插入到组件树中时 createState 函数由 Framework 调用,此函数在树中给定的地位为此组件创立 State,如果在组件树的不同地位都插入了此组件,即创立了多个此组件,如下:

Row(children: [MyStatefulWidget(),
  MyStatefulWidget(),
  MyStatefulWidget(),],)

那么零碎会为每一个组件创立一个独自的 State,当组件从组件树中移除,而后从新插入到组件树中时,createState 函数将会被调用创立一个新的 State

createState 函数执行结束后示意以后组件曾经在组件树中,此时有一个十分重要的属性 mountedFramework 设置为 true

生命周期二:initState

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

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

如果此组件须要订阅告诉,比方 ChangeNotifier 或者 Stream,则须要在不同的生命周期内正确处理订阅和勾销订阅告诉。

  • initState 中订阅告诉。
  • didUpdateWidget 中,如果须要替换旧组件,则在旧对象中勾销订阅,并在新对象中订阅告诉。
  • 并在 dispose 中勾销订阅。

另外在此函数中不能调用 BuildContext.dependOnInheritedWidgetOfExactType,典型的谬误写法如下:

@override
void initState() {super.initState();
  IconTheme iconTheme = context.dependOnInheritedWidgetOfExactType<IconTheme>();}

异样信息如下:

解决方案:

@override
void didChangeDependencies() {super.didChangeDependencies();
  context.dependOnInheritedWidgetOfExactType<IconTheme>();}

下面的用法作为初学者应用的比拟少,但上面的错误代码大部分应该都写过:

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

异样信息如下:

解决方案:

@override
void initState() {super.initState();
  WidgetsBinding.instance.addPostFrameCallback((timeStamp) {showDialog(context: context,builder: (context){return AlertDialog(title: Text('AlertDialog'),);
    });
  });
}

留神:弹出 AlertDialog 在 didChangeDependencies 中调用也会出现异常,但和下面的异样不是同一个。

生命周期三: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 对象的组件属性以援用新的组件,而后应用先前的组件作为参数调用此办法。

@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。调用完 dispose后,mounted 属性被设置为 false,也代表组件生命周期的完结,此时再调用 setState 办法将会抛出异样。

子类重写此办法,开释相干资源,比方动画等。

十分重要的几个概念

上面介绍几个十分重要的概念和办法,这些并不是生命周期的一部分,然而生命周期过程中的产物,与生命周期关系十分严密。

mounted

mounted 是 State 对象中的一个属性,此属性示意以后组件是否在树中,在创立 State 之后,调用 initState 之前,Framework 会将 StateBuildContext 进行关联,当 Framework 调用 dispose 时,mounted 被设置为 false,示意以后组件曾经不在树中。

createState 函数执行结束后示意以后组件曾经在组件树中,属性 mountedFramework 设置为 true,平时写代码时或者看其余开源代码时常常看到如下代码:

if(mounted){setState(() {...});
}

强烈建议:在调用 setState 时加上 mounted 判断。

为什么要加上如此判断?因为如果以后组件未插入到树中或者曾经从树中移除时,调用 setState 会抛出异样,加上 mounted 判断,则示意以后组件在树中。

dirty 和 clean

dirty 示意组件以后的状态为 脏状态,下一帧时将会执行 build 函数,调用 setState 办法或者 执行 didUpdateWidget 办法后,组件的状态为 dirty

cleandirty 绝对应,clean 示意组件以后的状态为 洁净状态clean 状态下组件不会执行 build 函数。

setState

setState 办法是开发者常常调用的办法,此办法调用后,组件的状态变为 dirty,当有数据要更新时,调用此办法。

reassemble

reassemble 用于开发,比方 hot reload,在 release 版本中不会回调此办法。

交换

老孟 Flutter 博客(330 个控件用法 + 实战入门系列文章):http://laomengit.com

欢送退出 Flutter 交换群(微信:laomengit)、关注公众号【老孟 Flutter】:

正文完
 0