做過Android/iOS開發(fā)的都知道我們的頁面都是由生命周期今魔,我們在不同生命周期的回調(diào)方法里會做一些處理。對于flutter而言 一切皆是Widget闪唆,所以了解Widget的生命周期也是必不可少的!
那我們先從簡單的StateLessWidget開始吧钓葫。
下圖是官網(wǎng)對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的定義也是很簡單帆调,就三個方法。構(gòu)造方法很好理解豆同,build方法其實就是我們自己實現(xiàn)如何構(gòu)建布局我們的頁面的番刊。createElement我們基本在開發(fā)中不會用到,那它做了些什么呢影锈?以下是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方法里調(diào)用了widget 的build方法芹务,并且將當(dāng)前element傳到了widget的build方法里,也就對應(yīng)著我們經(jīng)逞纪ⅲ看到的build(BuildContext context)枣抱,其實BuildContext 就是element。upate方法感覺應(yīng)該是更新的時候調(diào)用的辆床。那么到底是在哪調(diào)的呢佳晶,什么時候調(diào)的呢?我們繼續(xù)跟進下ComponentElement的源碼:
class ComponentElement extends Element{
@override
void performRebuild() {
………
Widget build;
build = build();
………
_child = updateChild(_child, build, slot);
…………
}
}
由于代碼篇幅較大讼载,摘出重點轿秧≈械可以看到performRebuild這個方法里調(diào)用了build方法,StatelessElement里的build方法又調(diào)用到了widget里的build方法菇篡。到這 StateLessWidget的聲明周期已經(jīng)完事了漩符。相信你一定有不少疑問,比如 那什么時候顯示驱还,什么時候銷毀陨仅,ComponentElement的performRebuild方法又是什么時候調(diào)用的呢?這里先只做Widget內(nèi)方法調(diào)用順序的分析铝侵,以上問題會在啟動流程部分給出解答灼伤,別著急哈。
StatefulWidget的生命周期
我們知道StatefulWidget是有狀態(tài)的Widget咪鲜,Widget創(chuàng)建出來之后是不可變狐赡,但是狀態(tài)是可以變的,管理這個狀態(tài)的就是State疟丙,我們可以通過調(diào)用期setState方法去刷新Widget颖侄。先看個我們平時寫StatefulWidget的例子:
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
@override
_MyStatefulWidget createState() => _MyStatefulWidget();
}
class _MyStatefulWidget extends State<MyStatefulWidget> {
@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 是啥時候調(diào)用的炊琉。
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構(gòu)造的時候就創(chuàng)建了展蒂,同時發(fā)現(xiàn)_firstBuild 好像是第一次創(chuàng)建的意思,我們來看看 這里做了啥苔咪,果然在這里調(diào)用了initState 方法锰悼,之后是didChangeDependencies,那build方法是啥時候調(diào)用的呢团赏?我們看看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()會觸發(fā)rebuild()函數(shù),rebuild()函數(shù)又會觸發(fā)performRebuild(),在performRebuild()函數(shù)里我們看到調(diào)用了build()函數(shù)舔清,至此StatefulWidget的創(chuàng)建過程基本完事丝里。我們可以看到在performRebuild里調(diào)用了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体谒,這個方法是將當(dāng)前element標(biāo)注為不活躍杯聚,暫時不會顯示在屏幕上。此時會調(diào)用State的deactivate营密,不能在該方法內(nèi)做銷毀資源操作械媒,因為該element有可能會再次被置為活躍狀態(tài)目锭。當(dāng)我們執(zhí)行了pop评汰,framework會觸發(fā)unmount()函數(shù)纷捞,state dispose會被調(diào)用,我們可以在這個方法里做資源銷毀被去。
總結(jié)下StatefulWidget生命周期:
- initState 適合做初始化工作
- build 避免在build內(nèi)做些邏輯代碼主儡,因為在調(diào)用setState是build方法會重新觸發(fā),容易產(chǎn)生問題
- dispose 釋放資源惨缆。
到這里我們就StateLessWidget糜值,StatefulWidget的聲明周期分析完了。本次的分析是基于widget和state內(nèi)方法調(diào)用順序為思路分析的坯墨,對于element內(nèi)的方法調(diào)用順序會在接下來的 flutter app啟動流程里分析寂汇。
歡迎拍磚,交流捣染!