
老孟導讀:關于生命周期的文章共有2篇,第一篇是介紹 Flutter 中Stateful 組件的生命周期,
博客地址:http://laomengit.com/blog/20201227/Stateful%E7%BB%84%E4%BB%B6%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.html第二篇是 Flutter 中與平臺相關的生命周期,
博客地址:http://laomengit.com/blog/20201227/%E7%9B%B8%E5%85%B3%E5%B9%B3%E5%8F%B0%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.html
博客中還有更多精彩文章,也歡迎加入 Flutter 交流群,
此篇文章介紹 StatefulWidget 組件的生命周期, StatefulWidget 組件的生命周期時非常重要的知識點,就像 Android 中 Activity 的生命周期一樣,不僅在以后的作業中經常用到,面試也會經常被問到,
在 Flutter 中一切皆 組件,而組件又分為 StatefulWidget(有狀態) 和 StatelessWidget(無狀態)組件 ,他們之間的區別是 StatelessWidget 組件發生變化時必須重新創建新的實體,而 StatefulWidget 組件則可以直接改變當前組件的狀態而無需重新創建新的實體,
注意:使用的 Flutter 版本 和 Dart 版本如下:
Flutter 1.22.4 ? channel stable ? https://github.com/flutter/flutter.git
Framework ? revision 1aafb3a8b9 (6 weeks ago) ? 2020-11-13 09:59:28 -0800
Engine ? revision 2c956a31c0
Tools ? Dart 2.10.4不同的版本 StatefulWidget 組件的生命周期會有差異,
下面的 StatefulWidget 和 State 結構圖是StatefulWidget 組件生命周期的概覽,不同版本的差異也可以對比此結構圖,

生命周期流程圖:

下面詳細介紹 StatefulWidget 組件的生命周期,
生命周期一:createState
下面是一個非常簡單的 StatefulWidget 組件:
class StatefulWidgetDemo extends StatefulWidget {
@override
_StatefulWidgetDemoState createState() => _StatefulWidgetDemoState();
}
class _StatefulWidgetDemoState extends State<StatefulWidgetDemo> {
@override
Widget build(BuildContext context) {
return Container();
}
}
當我們構建一個 StatefulWidget 組件時,首先執行其建構式(上面的代碼沒有顯示的建構式,但有默認的無參建構式),然后執行 createState 函式,但建構式并不是生命周期的一部分,
當 StatefulWidget 組件插入到組件樹中時 createState 函式由 Framework 呼叫,此函式在樹中給定的位置為此組件創建 State,如果在組件樹的不同位置都插入了此組件,即創建了多個此組件,如下:
Row(children: [
MyStatefulWidget(),
MyStatefulWidget(),
MyStatefulWidget(),
],)
那么系統會為每一個組件創建一個單獨的 State,當組件從組件樹中移除,然后重新插入到組件樹中時, createState 函式將會被呼叫創建一個新的 State,
createState 函式執行完畢后表示當前組件已經在組件樹中,此時有一個非常重要的屬性 mounted 被 Framework 設定為 true,
生命周期二:initState
initState 函式在組件被插入樹中時被 Framework 呼叫(在 createState 之后),此函式只會被呼叫一次,子類通常會重寫此方法,在其中進行初始化操作,比如加載網路資料,重寫此方法時一定要呼叫 super.initState(),如下:
@override
void initState() {
super.initState();
//初始化...
}
如果此組件需要訂閱通知,比如 ChangeNotifier 或者 Stream,則需要在不同的生命周期內正確處理訂閱和取消訂閱通知,
- 在 initState 中訂閱通知,
- 在 didUpdateWidget 中,如果需要替換舊組件,則在舊物件中取消訂閱,并在新物件中訂閱通知,
- 并在 dispose 中取消訂閱,
另外在此函式中不能呼叫 BuildContext.dependOnInheritedWidgetOfExactType,典型的錯誤寫法如下:
@override
void initState() {
super.initState();
IconTheme iconTheme = context.dependOnInheritedWidgetOfExactType<IconTheme>();
}
例外資訊如下:

解決方案:
@override
void didChangeDependencies() {
super.didChangeDependencies();
context.dependOnInheritedWidgetOfExactType<IconTheme>();
}
上面的用法作為初學者使用的比較少,但下面的錯誤代碼大部分應該都寫過:
@override
void initState() {
super.initState();
showDialog(context: context,builder: (context){
return AlertDialog();
});
}
例外資訊如下:

解決方案:
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
showDialog(context: context,builder: (context){
return AlertDialog(title: Text('AlertDialog'),);
});
});
}
注意:彈出 AlertDialog 在 didChangeDependencies 中呼叫也會出現例外,但和上面的例外不是同一個,
生命周期三:didChangeDependencies
didChangeDependencies 方法在 initState 之后由 Framework 立即呼叫,另外,當此 State 物件的依賴項更改時被呼叫,比如其所依賴的 InheritedWidget 發生變化時, Framework 會呼叫此方法通知組件發生變化,
此方法是生命周期中第一個可以使用 BuildContext.dependOnInheritedWidgetOfExactType 的方法,此方法很少會被重寫,因為 Framework 會在依賴發生變化時呼叫 build,需要重寫此方法的場景是:依賴發生變化時需要做一些耗時任務,比如網路請求資料,
didChangeDependencies 方法呼叫后,組件的狀態變為 dirty,立即呼叫 build 方法,
生命周期四:build
此方法是我們最熟悉的,在方法中創建各種組件,繪制到螢屏上, Framework會在多種情況下呼叫此方法:
- 呼叫 initState 方法后,
- 呼叫 didUpdateWidget 方法后,
- 收到對 setState 的呼叫后,
- 此 State 物件的依存關系發生更改后(例如,依賴的 InheritedWidget 發生了更改),
- 呼叫 deactivate 之后,然后將 State 物件重新插入樹的另一個位置,
此方法可以在每一幀中呼叫,此方法中應該只包含構建組件的代碼,不應該包含其他額外的功能,尤其是耗時任務,
生命周期五:didUpdateWidget
當組件的 configuration 發生變化時呼叫此函式,當父組件使用相同的 runtimeType 和 Widget.key 重新構建一個新的組件時,Framework 將更新此 State 物件的組件屬性以參考新的組件,然后使用先前的組件作為引數呼叫此方法,
@override
void didUpdateWidget(covariant StatefulLifecycle oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget');
}
此方法中通常會用當前組件與前組件進行對比,Framework 呼叫完此方法后,會將組件設定為 dirty 狀態,然后呼叫 build 方法,因此無需在此方法中呼叫 setState 方法,
生命周期六:deactivate
當框架從樹中移除此 State 物件時將會呼叫此方法,在某些情況下,框架將重新插入 State 物件到樹的其他位置(例如,如果包含該樹的子樹 State 物件從樹中的一個位置移植到另一位置),框架將會呼叫 build 方法來提供 State 物件適應其在樹中的新位置,
生命周期七:dispose
當框架從樹中永久移除此 State 物件時將會呼叫此方法,與 deactivate 的區別是,deactivate 還可以重新插入到樹中,而 dispose 表示此 State 物件永遠不會在 build,呼叫完 dispose后,mounted 屬性被設定為 false,也代表組件生命周期的結束,此時再呼叫 setState 方法將會拋出例外,
子類重寫此方法,釋放相關資源,比如影片等,
非常重要的幾個概念
下面介紹幾個非常重要的概念和方法,這些并不是生命周期的一部分,但是生命周期程序中的產物,與生命周期關系非常緊密,
mounted
mounted 是 State 物件中的一個屬性,此屬性表示當前組件是否在樹中,在創建 State 之后,呼叫 initState 之前,Framework 會將 State 和 BuildContext 進行關聯,當 Framework 呼叫 dispose 時,mounted 被設定為 false,表示當前組件已經不在樹中,
createState 函式執行完畢后表示當前組件已經在組件樹中,屬性 mounted 被 Framework 設定為 true,平時寫代碼時或者看其他開源代碼時經常看到如下代碼:
if(mounted){
setState(() {
...
});
}
強烈建議:在呼叫 setState 時加上 mounted 判斷,
為什么要加上如此判斷?因為如果當前組件未插入到樹中或者已經從樹中移除時,呼叫 setState 會拋出例外,加上 mounted 判斷,則表示當前組件在樹中,
dirty 和 clean
dirty 表示組件當前的狀態為 臟狀態,下一幀時將會執行 build 函式,呼叫 setState 方法或者 執行 didUpdateWidget 方法后,組件的狀態為 dirty,
clean 與 dirty 相對應,clean 表示組件當前的狀態為 干凈狀態,clean 狀態下組件不會執行 build 函式,
setState
setState 方法是開發者經常呼叫的方法,此方法呼叫后,組件的狀態變為 dirty,當有資料要更新時,呼叫此方法,
reassemble
reassemble 用于開發,比如 hot reload ,在 release 版本中不會回呼此方法,
交流
老孟Flutter博客(330個控制元件用法+實戰入門系列文章):http://laomengit.com
歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:
![]() |
![]() |
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/242188.html
標籤:Dart


