一,概述
Flutter 的生命周期分為兩個部分:
- Widget 的生命周期
- App 的生命周期
二,Widget 的生命周期
Flutter 里的 Widget 分為 StatelessWidget 和 StatefulWidget 兩種,這兩種 Widget 的生命周期是不一樣的,我們接下來具體來看。
-
StatelessWidget 的生命周期
StatelessWidget 的生命周期只有一個,就是:
-
-
build
build 是用來創建 Widget 的,但因為 build 在每次界面刷新的時候都會調用,所以不要在 build 里寫業務邏輯,可以把業務邏輯寫到你的 StatelessWidget 的構造函數里。
StatelessWidget 的 build 函數代碼如下:
class TestWidget extends StatelessWidget{ @override Widget build(BuildContext context) { // TODO: implement build print('StatelessWidget build'); return Text('Test'); } }
-
-
StatefulWidget 的生命周期
-
StatefulWidget 的生命周期比較復雜,依次為:
-
-
- createState
- initState
- didChangeDependencies
- build
- addPostFrameCallback
- didUpdateWidget
- deactivate
- dispose
-
- 生命周期圖
- 接下來具體介紹一下各個生命周期。
-
createState
createState 是 StatefulWidget 里創建 State 的方法,當要創建新的 StatefulWidget 的時候,會立即執行 createState,而且只執行一次,createState 必須要實現:
class MyScreen extends StatefulWidget { @override _MyScreenState createState() => _MyScreenState(); }
-
initState
前面的 createState 是在創建 StatefulWidget 的時候會調用,initState 是 StatefulWidget 創建完后調用的第一個方法,而且只執行一次,類似於 Android 的 onCreate、iOS 的 viewDidLoad(),所以在這里 View 並沒有渲染,但是這時 StatefulWidget 已經被加載到渲染樹里了,這時 StatefulWidget 的 mount的值會變為 true,直到 dispose調用的時候才會變為 false。可以在 initState里做一些初始化的操作。
在 override initState的時候必須要調用 super.initState():
@override void initState() { super.initState(); ... }
-
didChangeDependencies
當 StatefulWidget 第一次創建的時候,didChangeDependencies方法會在 initState方法之后立即調用,之后當 StatefulWidget 刷新的時候,就不會調用了,除非你的 StatefulWidget 依賴的 InheritedWidget 發生變化之后,didChangeDependencies才會調用,所以 didChangeDependencies有可能會被調用多次。
這個函數會緊跟在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中,可以跨組件拿到數據。
-
build
在 StatefulWidget 第一次創建的時候,build方法會在 didChangeDependencies方法之后立即調用,另外一種會調用 build方法的場景是,每當 UI 需要重新渲染的時候(setState觸發),build都會被調用,所以 build會被多次調用,然后 返回要渲染的 Widget。千萬不要在 build里做除了創建 Widget 之外的操作,因為這個會影響 UI 的渲染效率。
-
addPostFrameCallback
addPostFrameCallback是 StatefulWidge 渲染結束的回調,只會被調用一次,之后 StatefulWidget 需要刷新 UI 也不會被調用,addPostFrameCallback的使用方法是在 initState里添加回調:
import 'package:flutter/scheduler.dart'; @override void initState() { super.initState(); SchedulerBinding.instance.addPostFrameCallback((_) => {}); }
-
didUpdateWidget
祖先節點rebuild widget時調用 .當組件的狀態改變的時候就會調用didUpdateWidget.(可能會調用多次)
理論上setState的時候會調用,但我實際操作的時候發現只是做setState的操作的時候沒有調用這個方法。而在我改變代碼hot reload時候會調用 didUpdateWidget 並執行 build…
實際上這里flutter框架會創建一個新的Widget,綁定本State,並在這個函數中傳遞老的Widget。這個函數一般用於比較新、老Widget,看看哪些屬性改變了,並對State做一些調整。
需要注意的是,涉及到controller的變更,需要在這個函數中移除老的controller的監聽,並創建新controller的監聽。
-
deactivate(組件移除時)
當要將 State 對象從渲染樹中移除的時候,就會調用 deactivate生命周期,這標志着 StatefulWidget 將要銷毀,但是有時候 State 不會被銷毀,而是重新插入到渲染樹種。
-
dispose(組件移除時)
當 View 不需要再顯示,從渲染樹中移除的時候,State 就會永久的從渲染樹中移除,就會調用 dispose生命周期,這時候就可以在 dispose里做一些取消監聽、動畫的操作,和 initState是相反的。
-
- 生命周期圖
三,App 的生命周期
AppLifecycleState 就是 App 的生命周期,有:
- resumed
- inactive
- paused
- suspending