做过Android/iOS开发的都知道我们的页面都是由生命周期,我们在不同生命周期的回调方法里会做一些处理。对于flutter而言 一切皆是Widget,所以了解Widget的生命周期也是必不可少的!
那我们先从简单的StateLessWidget开始吧。
下图是官网对StateLessWidget 生命周期的描述,不难看出StateLessWidget只有两个过程,初始化和build。
StateLessWidget 源码如下:
abstract class StatelessWidget extends Widget {
/// Initializes [key] for subclasses.
const StatelessWidget({ Key key }) : super(key: key);
/// Creates a [StatelessElement] to manage this widget's location in the tree.
///
/// It is uncommon for subclasses to override this method.
@override
StatelessElement createElement() => StatelessElement(this);
/// Describes the part of the user interface represented by this widget.
@protected
Widget build(BuildContext context);
}
StatelessWidget的定义也是很简单,就三个方法。构造方法很好理解,build方法其实就是我们自己实现如何构建布局我们的页面的。createElement我们基本在开发中不会用到,那它做了些什么呢?以下是StatelessElement的源码:
class StatelessElement extends ComponentElement {
/// Creates an element that uses the given widget as its configuration.
StatelessElement(StatelessWidget widget) : super(widget);
@override
StatelessWidget get widget => super.widget as StatelessWidget;
@override
Widget build() => widget.build(this);
@override
void update(StatelessWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
_dirty = true;
rebuild();
}
}
在StatelessElement 我们可以到build方法里调用了widget 的build方法,并且将当前element传到了widget的build方法里,也就对应着我们经常看到的build(BuildContext context),其实BuildContext 就是element。upate方法感觉应该是更新的时候调用的。那么到底是在哪调的呢,什么时候调的呢?我们继续跟进下ComponentElement的源码:
class ComponentElement extends Element{
@override
void performRebuild() {
………
Widget build;
build = build();
………
_child = updateChild(_child, build, slot);
…………
}
}
由于代码篇幅较大,摘出重点。可以看到performRebuild这个方法里调用了build方法,StatelessElement里的build方法又调用到了widget里的build方法。到这 StateLessWidget的声明周期已经完事了。相信你一定有不少疑问,比如 那什么时候显示,什么时候销毁,ComponentElement的performRebuild方法又是什么时候调用的呢?这里先只做Widget内方法调用顺序的分析,以上问题会在启动流程部分给出解答,别着急哈。
StatefulWidget的生命周期
我们知道StatefulWidget是有状态的Widget,Widget创建出来之后是不可变,但是状态是可以变的,管理这个状态的就是State,我们可以通过调用期setState方法去刷新Widget。先看个我们平时写StatefulWidget的例子:
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
@override
_MyStatefulWidget createState() => _MyStatefulWidget();
}
class _MyStatefulWidget extends State {
@override
Widget build(BuildContext context){
……………
}
}
我们在State里重写了build方法,记住这一点哟。跟StateLessWidget一样我们来看看StatefulWidget的源码:
class StatefulWidget extends Widget{
const StatefulWidget({Key key}) : super(key: key);
@override
StatefulElement createElement() => StatefulElement(this);
@proteced
State createState();
}
比StateLessWidget多了个createState方法,同样我们跟进StatefulElement,来探索下createState 是啥时候调用的。
class StatefulElement extends ComponentElement{
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget){
……………
}
……………
@override
void _firstBuild() {
………
final dynamic debugCheckForReturnedFuture = _state.initState();
………
_state.didChangeDependencies();
………
super._firstBuild()
}
……………
}
可以看到createState 在StatefulWidget构造的时候就创建了,同时发现_firstBuild 好像是第一次创建的意思,我们来看看 这里做了啥,果然在这里调用了initState 方法,之后是didChangeDependencies,那build方法是啥时候调用的呢?我们看看super._firstBuild()做了什么。
class ComponentElement extends Element{
void _firstBuild() {
rebuild();
}
void rebuild(){
.................
performRebuild();
.......
}
@override
void performRebuild() {
………
Widget build;
build = build();
………
_child = updateChild(_child, build, slot);
…………
}
}
其实这个super._firstBuild()会触发rebuild()函数,rebuild()函数又会触发performRebuild(),在performRebuild()函数里我们看到调用了build()函数,至此StatefulWidget的创建过程基本完事。我们可以看到在performRebuild里调用了updateChild,
Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
if (newWidget == null) {
if (child != null)
deactivateChild(child);//// widget不活跃
return null;
}
Element newChild;
if (child != null) {
bool hasSameSuperclass = true;
assert(() {
final int oldElementClass = Element._debugConcreteSubtype(child);
final int newWidgetClass = Widget._debugConcreteSubtype(newWidget);
hasSameSuperclass = oldElementClass == newWidgetClass;
return true;
}());
if (hasSameSuperclass && child.widget == newWidget) {
..........
} else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
..........
}());
newChild = child;
} else {
deactivateChild(child); //// widget不活跃
assert(child._parent == null);
newChild = inflateWidget(newWidget, newSlot);
}
} else {
.......
}
.............
return newChild;
}
在这里会看到deactivateChild,这个方法是将当前element标注为不活跃,暂时不会显示在屏幕上。此时会调用State的deactivate,不能在该方法内做销毁资源操作,因为该element有可能会再次被置为活跃状态。当我们执行了pop,framework会触发unmount()函数,state dispose会被调用,我们可以在这个方法里做资源销毁。
总结下StatefulWidget生命周期:
- initState 适合做初始化工作
- build 避免在build内做些逻辑代码,因为在调用setState是build方法会重新触发,容易产生问题
- dispose 释放资源。
到这里我们就StateLessWidget,StatefulWidget的声明周期分析完了。本次的分析是基于widget和state内方法调用顺序为思路分析的,对于element内的方法调用顺序会在接下来的 flutter app启动流程里分析。
欢迎拍砖,交流!