老孟导读 :对于生命周期的文章共有 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 函数执行结束后示意以后组件曾经在组件树中,此时有一个十分重要的属性 mounted 被 Framework 设置为 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 发生变化时调用此函数,当父组件应用雷同的 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。调用完 dispose后,mounted 属性被设置为 false,也代表组件生命周期的完结,此时再调用 setState 办法将会抛出异样。
子类重写此办法,开释相干资源,比方动画等。
十分重要的几个概念
上面介绍几个十分重要的概念和办法,这些并不是生命周期的一部分,然而生命周期过程中的产物,与生命周期关系十分严密。
mounted
mounted 是 State 对象中的一个属性,此属性示意以后组件是否在树中,在创立 State 之后,调用 initState 之前,Framework 会将 State 和 BuildContext 进行关联,当 Framework 调用 dispose 时,mounted 被设置为 false,示意以后组件曾经不在树中。
createState 函数执行结束后示意以后组件曾经在组件树中,属性 mounted 被 Framework 设置为 true,平时写代码时或者看其余开源代码时常常看到如下代码:
if(mounted){setState(() {...});
}
强烈建议:在调用 setState 时加上 mounted 判断。
为什么要加上如此判断?因为如果以后组件未插入到树中或者曾经从树中移除时,调用 setState 会抛出异样,加上 mounted 判断,则示意以后组件在树中。
dirty 和 clean
dirty 示意组件以后的状态为 脏状态,下一帧时将会执行 build 函数,调用 setState 办法或者 执行 didUpdateWidget 办法后,组件的状态为 dirty。
clean 与 dirty 绝对应,clean 示意组件以后的状态为 洁净状态,clean 状态下组件不会执行 build 函数。
setState
setState 办法是开发者常常调用的办法,此办法调用后,组件的状态变为 dirty,当有数据要更新时,调用此办法。
reassemble
reassemble 用于开发,比方 hot reload,在 release 版本中不会回调此办法。
交换
老孟 Flutter 博客(330 个控件用法 + 实战入门系列文章):http://laomengit.com
欢送退出 Flutter 交换群(微信:laomengit)、关注公众号【老孟 Flutter】: