一胁附,概述
Flutter 的生命周期分為兩個(gè)部分:
- Widget 的生命周期
- App 的生命周期
二酒繁,Widget 的生命周期
Flutter 里的 Widget 分為 StatelessWidget 和 StatefulWidget 兩種,這兩種 Widget 的生命周期是不一樣的控妻,我們接下來(lái)具體來(lái)看州袒。
-
StatelessWidget 的生命周期
StatelessWidget 的生命周期只有一個(gè),就是:
-
-
build
build 是用來(lái)創(chuàng)建 Widget 的弓候,但因?yàn)?build 在每次界面刷新的時(shí)候都會(huì)調(diào)用郎哭,所以不要在 build 里寫(xiě)業(yè)務(wù)邏輯,可以把業(yè)務(wù)邏輯寫(xiě)到你的 StatelessWidget 的構(gòu)造函數(shù)里菇存。
StatelessWidget 的 build 函數(shù)代碼如下:
class TestWidget extends StatelessWidget{ @override Widget build(BuildContext context) { // TODO: implement build print('StatelessWidget build'); return Text('Test'); } }
-
-
StatefulWidget 的生命周期
-
StatefulWidget 的生命周期比較復(fù)雜夸研,依次為:
-
- createState
- initState
- didChangeDependencies
- build
- addPostFrameCallback
- didUpdateWidget
- deactivate
- dispose
-
-
生命周期圖
image -
接下來(lái)具體介紹一下各個(gè)生命周期。
-
createState
createState 是 StatefulWidget 里創(chuàng)建 State 的方法依鸥,當(dāng)要?jiǎng)?chuàng)建新的 StatefulWidget 的時(shí)候亥至,會(huì)立即執(zhí)行 createState,而且只執(zhí)行一次,createState 必須要實(shí)現(xiàn):
class MyScreen extends StatefulWidget { @override _MyScreenState createState() => _MyScreenState(); }</pre>
-
initState
前面的 createState 是在創(chuàng)建 StatefulWidget 的時(shí)候會(huì)調(diào)用抬闯,initState 是 StatefulWidget 創(chuàng)建完后調(diào)用的第一個(gè)方法井辆,而且只執(zhí)行一次关筒,類似于 Android 的 onCreate溶握、iOS 的 viewDidLoad(),所以在這里 View 并沒(méi)有渲染蒸播,但是這時(shí) StatefulWidget 已經(jīng)被加載到渲染樹(shù)里了睡榆,這時(shí) StatefulWidget 的 mount的值會(huì)變?yōu)?true袍榆,直到 dispose調(diào)用的時(shí)候才會(huì)變?yōu)?false胀屿。可以在 initState里做一些初始化的操作包雀。
在 override initState的時(shí)候必須要調(diào)用 super.initState():
@override void initState() { super.initState(); }
* **didChangeDependencies** 當(dāng) StatefulWidget 第一次創(chuàng)建的時(shí)候宿崭,**didChangeDependencies**方法會(huì)在 **initState**方法之后立即調(diào)用,之后當(dāng) StatefulWidget 刷新的時(shí)候才写,就不會(huì)調(diào)用了葡兑,除非你的 StatefulWidget 依賴的 InheritedWidget 發(fā)生變化之后,**didChangeDependencies**才會(huì)調(diào)用赞草,所以 **didChangeDependencies**有可能會(huì)被調(diào)用多次讹堤。 這個(gè)函數(shù)會(huì)緊跟在initState之后調(diào)用,并且可以調(diào)用BuildContext.inheritFromWidgetOfExactType厨疙,那么BuildContext.inheritFromWidgetOfExactType的使用場(chǎng)景是什么呢洲守?最經(jīng)典的應(yīng)用場(chǎng)景是
-
new DefaultTabController(length: 3, child: new TabBar( tabs: [ "主頁(yè)","訂單","我的" ] .map( (data)=>new Text(data) ).toList(),</pre> TabBar本來(lái)需要定義一個(gè)TabController,但是在外面套一層DefaultTabController就不需要定義TabContrller了,看下源碼: ``` @override void didChangeDependencies() { super.didChangeDependencies(); _updateTabController(); _initIndicatorPainter(); } void _updateTabController() { final TabController newController = widget.controller ?? DefaultTabController.of(context); ... }</pre>
注意到這里DefaultTabController.of(context) <pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">static TabController of(BuildContext context) { final _TabControllerScope scope = context.inheritFromWidgetOfExactType(_TabControllerScope); return scope?.controller; }</pre> 實(shí)際上就是調(diào)用BuildContext.inheritFromWidgetOfExactType,也就說(shuō)在didChangeDependencies中沾凄,可以跨組件拿到數(shù)據(jù)梗醇。 * **build** 在 StatefulWidget 第一次創(chuàng)建的時(shí)候,**build**方法會(huì)在 **didChangeDependencies**方法之后立即調(diào)用撒蟀,另外一種會(huì)調(diào)用 **build**方法的場(chǎng)景是婴削,每當(dāng) UI 需要重新渲染的時(shí)候(**setState**觸發(fā)),**build**都會(huì)被調(diào)用牙肝,所以 **build**會(huì)被多次調(diào)用唉俗,然后 返回要渲染的 Widget。千萬(wàn)不要在 **build**里做除了創(chuàng)建 Widget 之外的操作配椭,因?yàn)檫@個(gè)會(huì)影響 UI 的渲染效率虫溜。 * **addPostFrameCallback** **addPostFrameCallback**是 StatefulWidge 渲染結(jié)束的回調(diào),只會(huì)被調(diào)用一次股缸,之后 StatefulWidget 需要刷新 UI 也不會(huì)被調(diào)用衡楞,**addPostFrameCallback**的使用方法是在 **initState**里添加回調(diào):
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">import 'package:flutter/scheduler.dart'; @override void initState() { super.initState(); SchedulerBinding.instance.addPostFrameCallback((_) => {}); }</pre> ``` * **didUpdateWidget** 祖先節(jié)點(diǎn)rebuild widget時(shí)調(diào)用 .當(dāng)組件的狀態(tài)改變的時(shí)候就會(huì)調(diào)用**didUpdateWidget**.(可能會(huì)調(diào)用多次) 理論上setState的時(shí)候會(huì)調(diào)用,但我實(shí)際操作的時(shí)候發(fā)現(xiàn)只是做setState的操作的時(shí)候沒(méi)有調(diào)用這個(gè)方法敦姻。而在我改變代碼hot reload時(shí)候會(huì)調(diào)用 **didUpdateWidget** 并執(zhí)行 **build…** 實(shí)際上這里flutter框架會(huì)創(chuàng)建一個(gè)**新的Widge**t,綁定**本State**瘾境,并在這個(gè)函數(shù)中傳遞老的Widget歧杏。這個(gè)函數(shù)一般用于比較新、老Widget迷守,看看哪些屬性改變了犬绒,并對(duì)State做一些調(diào)整。 需要注意的是兑凿,涉及到controller的變更凯力,需要在這個(gè)函數(shù)中移除老的**controller**的監(jiān)聽(tīng),并創(chuàng)建新**controller**的監(jiān)聽(tīng)礼华。 * **deactivate(組件移除時(shí))** 當(dāng)要將 State 對(duì)象從渲染樹(shù)中移除的時(shí)候咐鹤,就會(huì)調(diào)用 **deactivate**生命周期,這標(biāo)志著 StatefulWidget 將要銷毀圣絮,但是有時(shí)候 State 不會(huì)被銷毀祈惶,而是重新插入到渲染樹(shù)種。 * **dispose(組件移除時(shí))** 當(dāng) View 不需要再顯示扮匠,從渲染樹(shù)中移除的時(shí)候捧请,State 就會(huì)永久的從渲染樹(shù)中移除,就會(huì)調(diào)用 **dispose**生命周期餐禁,這時(shí)候就可以在 **dispose**里做一些取消監(jiān)聽(tīng)血久、動(dòng)畫(huà)的操作,和 **initState**是相反的帮非。
-
三氧吐,App 的生命周期
AppLifecycleState 就是 App 的生命周期,有:
- resumed
- inactive
- paused
- suspending
如果想要知道 Flutter App 的生命周期末盔,例如 Flutter 是在前臺(tái)還是在后臺(tái)筑舅,就需要使用到 WidgetsBindingObserver了,使用方法如下:
- State 的類 mix WidgetsBindingObserver:
class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
}
- 在 State 的 initState里添加監(jiān)聽(tīng):
@override void initState(){ super.initState();
WidgetsBinding.instance.addObserver(this);
}
- 在 State 的 dispose里移除監(jiān)聽(tīng):
@override void dispose() { // TODO: implement dispose
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}</pre>
- 在 State 里 override didChangeAppLifecycleState
...@overridevoid didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); if (state == AppLifecycleState.paused) { // went to Background
} if (state == AppLifecycleState.resumed) { // came back to Foreground
}
}