Flutter 生命周期包括了組件的生命周期以及App的生命周期歉闰。
一蹈集、組件生命周期
一個(gè)flutter組件主要分為無(wú)狀態(tài)組件(StatelessWidget)和有狀態(tài)組件(StatefulWidget)点晴,無(wú)狀態(tài)組件只在創(chuàng)建的時(shí)候渲染一次,創(chuàng)建完成后不能重新渲染,而有狀態(tài)組件可以根據(jù)交互或數(shù)據(jù)變化等,進(jìn)行多次渲染乌奇,本文組件生命周期專(zhuān)指有狀態(tài)組件的生命周期。
組件生命周期主要是:createState眯娱、initState礁苗、didChangeDependencies、reassemble徙缴、didUpdateWidget试伙、build、deactivate娜搂、dispose這幾個(gè)函數(shù),從函數(shù)名我們可以初步感知其作用吱抚,它們大致的流轉(zhuǎn)關(guān)系及作用如圖:
下面以一個(gè)簡(jiǎn)單的Demo驗(yàn)證這個(gè)流程
1.構(gòu)建一個(gè)簡(jiǎn)單的MyApp:
import 'package:flutter/material.dart';
import 'package:flutterlifecycledemo/ui/home_page.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
/// 初始化state,只會(huì)在第一次構(gòu)建組件時(shí)調(diào)用一次
///
/// 在此期間可以執(zhí)行State各變量的初始賦值
/// 同時(shí)可以在此處調(diào)用網(wǎng)絡(luò)請(qǐng)求,服務(wù)器返回?cái)?shù)據(jù)后通過(guò)setState刷新頁(yè)面,類(lèi)似于iOS中的ViewDidLoad方法
@override
void initState() {
super.initState();
print('initState_MyApp');
}
/// 該組件所依賴(lài)的State發(fā)生變化時(shí)觸發(fā),或者在initState(組件首次創(chuàng)建)后觸發(fā)
///
/// 該組件所依賴(lài)的State指全局的State,例如語(yǔ)言和主題等
/// 此方法會(huì)觸發(fā)build
@override
void didChangeDependencies() {
super.didChangeDependencies();
print('didChangeDependencies_MyApp');
}
/// 在debug模式下,每次熱重載都會(huì)觸發(fā)該函數(shù)
///
/// 主要是在開(kāi)發(fā)階段在此增加一些debug代碼,檢查代碼問(wèn)題
@override
void reassemble() {
super.reassemble();
print('reassemble_MyApp');
}
/// 組件重新構(gòu)建(如熱重載),父組件發(fā)生build的情況下觸發(fā)
///
/// 注意:
/// 父組件發(fā)生build,本組件(子組件)該方法才會(huì)被調(diào)用,并且該方法調(diào)用后一定會(huì)再調(diào)用本組件中的build方法
/// 并且父組件首次創(chuàng)建不會(huì)觸發(fā)
@override
void didUpdateWidget(MyApp oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget_HomePage');
}
/// 組件在被移除節(jié)點(diǎn)后被調(diào)用
///
/// 如果該組件被移除節(jié)點(diǎn),然后未被插入到其他節(jié)點(diǎn)時(shí),則會(huì)繼續(xù)調(diào)用dispose永久移除
@override
void deactivate() {
super.deactivate();
print('deactivate_MyApp');
}
/// 永久移除組件,釋放組件資源
@override
void dispose() {
super.dispose();
print('dispose_MyApp');
}
/// 構(gòu)建需要渲染的widget,會(huì)被多次調(diào)用(會(huì)被setState/didChangeDependencies/didUpdateWidget觸發(fā))
///
/// 只做返回Widget的相關(guān)邏輯
@override
Widget build(BuildContext context) {
print('build_MyApp');
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Color(0xff409eff),
brightness: Brightness.light, // 默認(rèn)狀態(tài)欄顏色
),
home: HomePage(),
);
}
}
2.HomPage實(shí)現(xiàn):
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
HomePage();
/// 創(chuàng)建state
///
/// 當(dāng)StatefulWidget被調(diào)用時(shí)會(huì)立即執(zhí)行
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool showProgressHud = true;
double cw = 60;
/// 模擬加載數(shù)據(jù)
void loadData(){
// 5秒后調(diào)用setState
Future.delayed(Duration(seconds: 5), (){
setState(() {
showProgressHud = false;
});
});
}
/// 初始化state,只會(huì)在第一次構(gòu)建組件時(shí)調(diào)用一次
///
/// 在此期間可以執(zhí)行State各變量的初始賦值
/// 同時(shí)可以在此處調(diào)用網(wǎng)絡(luò)請(qǐng)求,服務(wù)器返回?cái)?shù)據(jù)后通過(guò)setState刷新頁(yè)面,類(lèi)似于iOS中的ViewDidLoad方法
@override
void initState() {
super.initState();
print('initState_HomePage');
loadData();
}
/// 該組件所依賴(lài)的State發(fā)生變化時(shí)觸發(fā),或者在initState(組件首次創(chuàng)建)后觸發(fā)
///
/// 該組件所依賴(lài)的State指全局的State,例如語(yǔ)言和主題等
/// 此方法會(huì)觸發(fā)build
@override
void didChangeDependencies() {
super.didChangeDependencies();
print('didChangeDependencies_HomePage');
}
/// 在debug模式下,每次熱重載都會(huì)觸發(fā)該函數(shù)
///
/// 主要是在開(kāi)發(fā)階段在此增加一些debug代碼,檢查代碼問(wèn)題
@override
void reassemble() {
super.reassemble();
print('reassemble_HomePage');
}
/// 組件重新構(gòu)建(如熱重載),父組件發(fā)生build的情況下觸發(fā)
///
/// 注意:
/// 父組件發(fā)生build,本組件(子組件)該方法才會(huì)被調(diào)用,并且該方法調(diào)用后一定會(huì)再調(diào)用本組件中的build方法
/// 并且父組件首次創(chuàng)建不會(huì)觸發(fā)
@override
void didUpdateWidget(HomePage oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget_HomePage');
}
/// 組件在被移除節(jié)點(diǎn)后被調(diào)用
///
/// 如果該組件被移除節(jié)點(diǎn),然后未被插入到其他節(jié)點(diǎn)時(shí),則會(huì)繼續(xù)調(diào)用dispose永久移除
@override
void deactivate() {
super.deactivate();
print('deactivate_HomePage');
}
/// 永久移除組件,釋放組件資源
@override
void dispose() {
super.dispose();
print('dispose_HomePage');
}
/// 構(gòu)建需要渲染的widget,會(huì)被多次調(diào)用(會(huì)被setState/didChangeDependencies/didUpdateWidget觸發(fā))
///
/// 只做返回Widget的相關(guān)邏輯
@override
Widget build(BuildContext context) {
print('build_HomePage');
return Scaffold(
appBar: AppBar(
title: Text('Hello Flutter',style: TextStyle(color: Color(0xffffffff),fontSize: 16, fontWeight: FontWeight.bold),),
centerTitle: true,
actions: <Widget>[
FlatButton( // 觸發(fā)setState,showProgressHud=true,當(dāng)前HomeConent組件會(huì)被移除
child: Text('loadData',style: TextStyle(color: Color(0xffffffff),fontSize: 14),),
onPressed: (){
setState(() {
showProgressHud = true;
loadData();
});
},
),
FlatButton( // 增加cw值,并只觸發(fā)setState,showProgressHud不變,當(dāng)前SubHomePage組件不會(huì)被移除
child: Text('click',style: TextStyle(color: Color(0xffffffff),fontSize: 14),),
onPressed: (){
setState(() {
cw += 10;
});
},
),
],
),
body: Container(
decoration: BoxDecoration(
color: Color(0xffffffff),
),
child: Center(
child: showProgressHud ?
CircularProgressIndicator() :
Column(
mainAxisAlignment: MainAxisAlignment.center ,
children: <Widget>[
Container(width: cw, height: 44,color: Color(0xff889eff),),
SubHomePage()
],
)
,
),
),
);
}
}
3.SubHomePage實(shí)現(xiàn):
class SubHomePage extends StatefulWidget {
@override
_SubHomePageState createState() => _SubHomePageState();
}
class _SubHomePageState extends State<SubHomePage> {
/// 初始化state,只會(huì)在第一次構(gòu)建組件時(shí)調(diào)用一次
///
/// 在此期間可以執(zhí)行State各變量的初始賦值
/// 同時(shí)可以在此處調(diào)用網(wǎng)絡(luò)請(qǐng)求,服務(wù)器返回?cái)?shù)據(jù)后通過(guò)setState刷新頁(yè)面,類(lèi)似于iOS中的ViewDidLoad方法
@override
void initState() {
super.initState();
print('initState_SubHomePage');
}
/// 該組件所依賴(lài)的State發(fā)生變化時(shí)觸發(fā),或者在initState(組件首次創(chuàng)建)后觸發(fā)
///
/// 該組件所依賴(lài)的State指全局的State,例如語(yǔ)言和主題等
/// 子類(lèi)很少重寫(xiě)這個(gè)方法,非必要情況不用重寫(xiě)此方法
/// 此方法會(huì)觸發(fā)build
@override
void didChangeDependencies() {
super.didChangeDependencies();
print('didChangeDependencies_SubHomePage');
}
/// 在debug模式下,每次熱重載都會(huì)觸發(fā)該函數(shù)
///
/// 主要是在開(kāi)發(fā)階段在此增加一些debug代碼,檢查代碼問(wèn)題
@override
void reassemble() {
super.reassemble();
print('reassemble_SubHomePage');
}
/// 組件重新構(gòu)建(如熱重載),父組件發(fā)生build的情況下觸發(fā)
///
/// 注意:
/// 父組件發(fā)生build,本組件(子組件)該方法才會(huì)被調(diào)用,并且該方法調(diào)用后一定會(huì)再調(diào)用本組件中的build方法
/// 并且父組件首次創(chuàng)建不會(huì)觸發(fā)
@override
void didUpdateWidget(SubHomePage oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget_SubHomePage');
}
/// 組件在被移除節(jié)點(diǎn)后被調(diào)用
///
/// 如果該組件被移除節(jié)點(diǎn),然后未被插入到其他節(jié)點(diǎn)時(shí),則會(huì)繼續(xù)調(diào)用dispose永久移除
@override
void deactivate() {
super.deactivate();
print('deactivate_SubHomePage');
}
/// 永久移除組件,釋放組件資源
@override
void dispose() {
super.dispose();
print('dispose_SubHomePage');
}
/// 構(gòu)建需要渲染的widget,會(huì)被多次調(diào)用(會(huì)被setState/didChangeDependencies/didUpdateWidget觸發(fā))
///
/// 只做返回Widget的相關(guān)邏輯
@override
Widget build(BuildContext context) {
print('build_SubHomePage');
return Column(
children: <Widget>[
Container(height: 100,),
Text('Welcome to flutter', style: TextStyle(color: Color(0xff333333), fontSize: 16),),
Container(
height: 10,
),
FlatButton(
onPressed: increaseAction,
child: Text(
'Increase',
style: TextStyle(color: Color(0xffffffff), fontSize: 14),
),
color: Color(0xff409eff),
)
],
);
}
void increaseAction(){
setState(() {
});
}
}
頁(yè)面效果:
首次加載控制臺(tái)輸出:
正好驗(yàn)證了首次加載有狀態(tài)組件的生命周期百宇,其中build_HomePage打印了兩次,是因?yàn)镠omePage在initState的時(shí)候調(diào)用了模擬網(wǎng)絡(luò)請(qǐng)求方法loadData,在請(qǐng)求完畢后調(diào)用了setState,從而觸發(fā)了HomePage的build秘豹。
接著點(diǎn)擊導(dǎo)航欄上的loadData(屬于HomePage的組件)按鈕携御,觸發(fā):
FlatButton( // 觸發(fā)setState,showProgressHud=true,當(dāng)前SubHomePage組件會(huì)被移除
child: Text('loadData',style: TextStyle(color: Color(0xffffffff),fontSize: 14),),
onPressed: (){
setState(() {
showProgressHud = true;
loadData();
});
},
),
此時(shí)控制臺(tái)輸出:
我們發(fā)現(xiàn)首次生成的SubHomePage被移除了,并且loadData完成后生成新的SubHomePage,新的SubHomePage會(huì)接著走新的首次加載流程
child: Center(
child: showProgressHud ?
CircularProgressIndicator() :
Column(
mainAxisAlignment: MainAxisAlignment.center ,
children: <Widget>[
Container(width: cw, height: 44,color: Color(0xff889eff),),
SubHomePage()
],
)
,
),
此時(shí)我們點(diǎn)HomePage導(dǎo)航欄上的click按鈕 既绕,增加矩形的寬度:
FlatButton( // 增加cw值,并只觸發(fā)setState,showProgressHud不變,當(dāng)前SubHomePage組件不會(huì)被移除
child: Text('click',style: TextStyle(color: Color(0xffffffff),fontSize: 14),),
onPressed: (){
setState(() {
cw += 10;
});
},
),
控制臺(tái)輸出:
此時(shí)我們可以看到HomePage的build觸發(fā)了其子組件SubHomePage的didUpdateWidget和build方法啄刹,但是SubHomePage仍然是原來(lái)的SubHomePage,并未重新釋放(如果釋放后重構(gòu)會(huì)調(diào)用dispose和initState),只是重新build了一次凄贩。
點(diǎn)擊SubHomePage上的increase,控制臺(tái)輸出:
cmd+\ 熱重載誓军,控制臺(tái)輸出:
二、App生命周期
app生命周期比較簡(jiǎn)單,具體可以參考官方文檔