生命周期是一個從建立到銷毀的過程,Flutter生命周期分為兩部分:
1.Widget的生命周期
2.APP的生命周期
我們先看Widget的生命周期
一、Widget的生命周期
1.StatelessWidget
對于StatelessWidget來說,生命周期隻有build過程。build是用來建立Widget的,在每次頁面重新整理時會調用build。
2.StatefulWidget
StatefulWidget的生命周期依次為:
initState:當Widget第一次插入到Widget樹時會被調用,對于每一個State對象,這個方法隻會調用一次。是以,通常在該回調中做一些一次性的操作,如一些初始化操作。(注意:不能在該回調中調用BuildContext.inheritFromWidgetOfExactType(該方法用于在Widget樹上擷取離目前widget最近的一個父級InheritFromWidget),原因是在初始化完成後,Widget樹中的InheritFromWidget也可能會發生變化,是以正确的做法應該在在build()方法或didChangeDependencies()中調用它。)
didChangeDependencies():當State對象的依賴發生變化時會被調用;
這個方法在兩種情況下會調用:
情況一:調用initState會調用;
情況二:從其他對象中依賴一些資料發生改變時,比如前面我們提到的InheritedWidget;
build:它主要是用于建構Widget子樹
reassemble:此回調是專門為了開發調試而提供的,在熱重載(hot reload)時會被調用,此回調在Release模式下永遠不會被調用。
didUpdateWidget:在widget重新建構時,Flutter framework會調用Widget.canUpdate來檢測Widget樹中同一位置的新舊節點,然後決定是否需要更新,如果Widget.canUpdate傳回true則會調用此回調。正如之前所述,Widget.canUpdate會在新舊widget的key和runtimeType同時相等時會傳回true,也就是說在在新舊widget的key和runtimeType同時相等時didUpdateWidget()就會被調用。
deactivate:當State對象從樹中被移除時,會調用此回調。在一些場景下,Flutter framework會将State對象重新插到樹中,如包含此State對象的子樹在樹的一個位置移動到另一個位置時(可以通過GlobalKey來實作)。如果移除後沒有重新插入到樹中則緊接着會調用dispose()方法。
dispose:當State對象從樹中被永久移除時調用;通常在此回調中釋放資源。
生命周期圖如下
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SOiJGO5EWN2gTZyYDM4EDZxITNmZWZkR2YjhTOmZWM58CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
示例如下
class Life extends StatefulWidget {
@override
_TestLifeState createState() => _TestLifeState();
}
class _TestLifeState extends State<Life> with WidgetsBindingObserver {
String title = "點選父元件";
@override
void initState() {
// TODO: implement initState
super.initState();
print('page1--initState');
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print(state.toString());
}
@override
void didChangeDependencies() {
print('test-page1--didChangeDependencies');
super.didChangeDependencies();
}
@override
void didUpdateWidget(Life oldWidget) {
print('test-page1--didUpdateWidget');
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
print('test-page1--build');
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text("生命周期示例"),
),
body: Column(
children: <Widget>[
GestureDetector(
child: new Text(title ?? ""),
onTap: () {
setState(() {
title = "父元件變化了";
});
},
),
Container(
width: 100,
height: 50,
child: Column (children: [
],),
),
ChildStatefulWidget(),
FlatButton(
color: Colors.grey,
onPressed: () {
Navigator.of(context)
.push(new MaterialPageRoute(builder: (BuildContext c) {
return new TestLifeCyclePage2();
}));
},
child: Text("跳轉頁面")),
],
),
);
}
@override
void reassemble() {
// TODO: implement reassemble
super.reassemble();
print('test-page1--reassemble');
}
@override
void deactivate() {
// TODO: implement deactivate
super.deactivate();
print('test-page1--deactivate');
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
//WidgetsBinding.instance.addObserver(this);
print('test-page1--dispose');
}
}
class ChildStatefulWidget extends StatefulWidget {
@override
_ChildStatefulWidgetState createState() {
print("child--createState");
return _ChildStatefulWidgetState();
}
}
class _ChildStatefulWidgetState extends State<ChildStatefulWidget> {
String title = "點選子元件";
@override
Widget build(BuildContext context) {
print('child--build');
return GestureDetector(
child: new Text(title ?? ""),
onTap: () {
setState(() {
title = "子元件變化了";
});
},
);
}
@override
void initState() {
print('child--initState');
super.initState();
}
@override
void didChangeDependencies() {
print('child--didChangeDependencies');
super.didChangeDependencies();
}
@override
void didUpdateWidget(ChildStatefulWidget oldWidget) {
print('child--didUpdateWidget');
super.didUpdateWidget(oldWidget);
}
@override
void reassemble() {
print('child--reassemble');
super.reassemble();
}
@override
void deactivate() {
print('child--deactivate');
super.deactivate();
}
@override
void dispose() {
print('child--dispose');
super.dispose();
//WidgetsBinding.instance.addObserver(this);
}
}
class TestLifeCyclePage2 extends StatefulWidget {
@override
_Test2LifeCyclePageState createState(){
return new _Test2LifeCyclePageState();
}
@override
StatefulElement createElement() {
// TODO: implement createElement
// print("page2--createElement");
return super.createElement();
}
}
class _Test2LifeCyclePageState extends State<TestLifeCyclePage2> with WidgetsBindingObserver {
@override
void initState() {
// TODO: implement initState
super.initState();
print('test-page2---initState');
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print(state.toString());
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
print('test-page2---didChangeDependencies');
}
@override
void didUpdateWidget(TestLifeCyclePage2 oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
print('test-page2---didUpdateWidget');
}
@override
Widget build(BuildContext context) {
print('page2---build');
// TODO: implement build
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text("生命周期示例2"),
),
);
}
@override
void reassemble() {
// TODO: implement reassemble
super.reassemble();
print('test-page2---reassemble');
}
@override
void deactivate() {
// TODO: implement deactivate
super.deactivate();
print('test-page2---deactivate');
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
//WidgetsBinding.instance.addObserver(this);
print('test-page2---dispose');
}
}
進入page1 生命周期
點選父元件setState的生命周期
點選子元件的生命周期
進入page2 的生命周期
退出page2 的生命周期
點選熱重載按鈕的生命周期
二、 App的生命周期
App的生命周期需要通過WidgetsBindingObserver的didChangeAppLifecycleState來擷取,在initState中添加監聽
WidgetsBinding.instance.addObserver(this);
resumed:可見并能響應使用者的輸入
inactive:處在并不活動狀态,無法處理使用者響應
paused:不可見并不能響應使用者的輸入,但是在背景繼續活動
app從前台退到背景的生命周期
app 從背景回到前台的生命周期
退出app的生命周期