前言
和其他的視圖框架比如android的Activity一樣,flutter中的視圖Widget也存在生命周期,生命周期的回調函數提現在了State上面。理解flutter的生命周期,對我們寫出一個合理的控件至關重要。組件State的生命周期整理如下圖所示:

大致可以看成三個階段
- 初始化(插入渲染樹)
- 狀態改變(在渲染樹中存在)
- 銷毀(從渲染樹種移除)
構造函數
這個函數不屬於生命周期,因為這個時候State的widget屬性為空,如果要在構造函數中訪問widget的屬性是行不通的。但是構造函數必然是要第一個調用的。
initState
/// Called when this object is inserted into the tree.
當插入渲染樹的時候調用,這個函數在生命周期中只調用一次。這里可以做一些初始化工作,比如初始化State的變量。
didChangeDependencies
/// Called when a dependency of this [State] object changes.

這個函數會緊跟在initState之后調用,並且可以調用BuildContext.inheritFromWidgetOfExactType,那么BuildContext.inheritFromWidgetOfExactType的使用場景是什么呢?最經典的應用場景是
new DefaultTabController(length: 3, child: new TabBar( tabs: [ "主頁","訂單","我的" ] .map( (data)=>new Text(data) ).toList(),
TabBar本來需要定義一個TabController,但是在外面套一層DefaultTabController就不需要定義TabContrller了,看下源碼:
@override void didChangeDependencies() { super.didChangeDependencies(); _updateTabController(); _initIndicatorPainter(); } void _updateTabController() { final TabController newController = widget.controller ?? DefaultTabController.of(context);
注意到這里DefaultTabController.of(context)
static TabController of(BuildContext context) { final _TabControllerScope scope = context.inheritFromWidgetOfExactType(_TabControllerScope); return scope?.controller; }
實際上就是調用BuildContext.inheritFromWidgetOfExactType,也就說在didChangeDependencies中,可以跨組件拿到數據。
didUpdateWidget
/// Called whenever the widget configuration changes.

當組件的狀態改變的時候就會調用didUpdateWidget,比如調用了setState.
實際上這里flutter框架會創建一個新的Widget,綁定本State,並在這個函數中傳遞老的Widget。
這個函數一般用於比較新、老Widget,看看哪些屬性改變了,並對State做一些調整。
需要注意的是,涉及到controller的變更,需要在這個函數中移除老的controller的監聽,並創建新controller的監聽。


deactivate
/// Called when this object is removed from the tree.
在dispose之前,會調用這個函數。
dispose
/// Called when this object is removed from the tree permanently.
一旦到這個階段,組件就要被銷毀了,這個函數一般會移除監聽,清理環境。
還是TabBar:

實際場景
假設我們從A頁面跳轉到B頁面, 那么A,B頁面的生命周期會是怎樣的呢?
B頁面進入初始化狀態,依次執行4個函數:構造函數 > initState > didChangeDependencies > Widget build , 此時頁面加載完成,進入運行態。
此時A頁面依次執行deactivate > build函數。注意 此時A頁面並未卸載。
然后我們假設B頁面只有一個按鈕,點擊B頁面中的按鈕,改變按鈕的文字,會執行widget的build方法 ,(理論上也應該執行didUpdateWidget,但我這里沒有)。
這時,我們點擊返回鍵從B頁面返回到A頁面。
A頁面重新顯示,B頁面開始卸載。
那么A先執行deactivate > build , 然后B頁面依次執行:deactivate > dispose 。
此時A頁面進入運行態,B頁面移除。
總結一下
階段 | 調用次數 | 是否支持setState |
---|---|---|
構造函數 | 1 | 否 |
initState | 1 | 無效(使用setState和不使用一樣) |
didChangeDependencies | >=1 | 無效 |
didUpdateWidget | >=1 | 是 |
deactivate | >=1 | 否 |
dispose | 1 | 否 |
作者:ershixiong
鏈接:https://www.jianshu.com/p/762bb2b7fa00
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。