Flutter檢視Widget生命週期
作為一個Android開發者,一定會對Activity的生命週期有這很深刻的印象,而當你在使用Flutter時,其中Widget就是View,其生命週期就是從View建立到銷燬的過程。 Widget分為StatelessWidgetStatefulWidget 兩種,這兩種Widget的生命週期分別如下。
StatelessWidget的生命週期
無狀態Widget的生命週期很簡單,它只有一個生命週期:build
build
build函式用來構建檢視,每次頁面重新整理是被呼叫,典型的用法如下:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Welcome to Flutter',
home: new Scaffold(
appBar: new AppBar(
title: new Text('Welcome to Flutter'),
),
body: new Center(
child: new Text('Hello World'),
),
),
);
}
}
複製程式碼
StatefulWidget的生命週期
StatefulWidget生命週期整理如下圖:
大致可分為三個階段:- 初始化:插入渲染樹
- 執行中:在渲染樹中存在
- 銷燬:從渲染樹中移除
初始化階段
createState
createState必須且僅執行一次,它用來建立state,當建立StatefulWidget時,該放方法被執行
initState
在建立StatefulWidget後,initState是第一個被呼叫的方法,同createState一樣只被呼叫一次,此時widget的被新增至渲染樹,mount的值會變為true,但並沒有渲染。可以在該方法內做一些初始化操作。在在override時要低啊用super.initState()
@override
void initState() {
super.initState();
...
}
複製程式碼
didChangeDependencies
當widget第一次被建立時,didChangeDependencies緊跟著initState函式之後呼叫,在widget重新整理時,該方法不會被呼叫。它會在“依賴”發生變化時被Flutter Framework呼叫,這個依賴是指widget是否使用父widget中InheritedWidget的資料。也即是隻有在widget依賴的InheritedWidget發生變化之後,didChangeDependencies才會呼叫。 這種機制可以使子元件在所依賴的InheritedWidget變化時來更新自身!比如當主題、locale(語言)等發生變化時,依賴其的子widget的didChangeDependencies方法將會被呼叫。
//通過繼承InheritedWidget,將當前計數器點選次數儲存在ShareDataWidget的data屬性中:
class ShareDataWidget extends InheritedWidget {
ShareDataWidget({
@required this.data,
Widget child
}) :super(child: child);
final int data; //需要在子樹中共享的資料,儲存點選次數
//定義一個便捷方法,方便子樹中的widget獲取共享資料
static ShareDataWidget of(BuildContext context) {
return context.inheritFromWidgetOfExactType(ShareDataWidget);
}
//該回撥決定當data發生變化時,是否通知子樹中依賴data的Widget
@override
bool updateShouldNotify(ShareDataWidget old) {
//如果返回true,則子樹中依賴(build函式中有呼叫)本widget
//的子widget的`state.didChangeDependencies`會被呼叫
return old.data != data;
}
}
class _TestWidget extends StatefulWidget {
@override
__TestWidgetState createState() => new __TestWidgetState();
}
//然後我們實現一個子元件_TestWidget,在其build方法中引用ShareDataWidget中的資料。
class __TestWidgetState extends State<_TestWidget> {
@override
Widget build(BuildContext context) {
//使用InheritedWidget中的共享資料
return Text(ShareDataWidget
.of(context)
.data
.toString());
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時會被呼叫。
//如果build中沒有依賴InheritedWidget,則此回撥不會被呼叫。
print("Dependencies change");
}
}
複製程式碼
注意:如果_TestWidget的build方法中沒有使用ShareDataWidget的資料,那麼它的didChangeDependencies()將不會被呼叫,因為它並沒有依賴ShareDataWidget。在依賴改變之後build方法也會被呼叫,所以在大多數場景下都無需使用didChangeDependencies。然而如果你需要在依賴改變後執行一些昂貴的操作,比如網路請求,這時最好的方式就是在此方法中執行,這樣可以避免每次build()都執行這些昂貴操作。
build
build函式會在widget第一次建立時緊跟著didChangeDependencies方法之後和UI重新渲染是時呼叫。build只做widget的建立操作,如果在build裡做其他操作,會影響UI的渲染效果
執行中
didUpdateWidget
當元件的狀態改變的時候就會呼叫didUpdateWidget,比如呼叫了setState.
銷燬
deactivate
當要將State物件從渲染樹中移除的時候,就會呼叫 deactivate 生命週期,這標誌著 StatefulWidget將要銷燬。頁面切換時,也會呼叫它,因為此時State在檢視樹中的位置發生了變化但是State不會被銷燬,而是重新插入到渲染樹中。 重寫的時候必須要呼叫 super.deactivate()
dispose
從渲染樹中移除view的時候呼叫,State會永久的從渲染樹中移除,和initState正好相反mount值變味false。這時候就可以在dispose裡做一些取消監聽操作。
總結:
函式 | 呼叫次數 | 呼叫時間 |
---|---|---|
createState | 1 | 第一次建立 |
initState | 1 | 第一次建立 |
didChangeDependencies | n | 第一次建立和依賴變化時 |
build | n | 第一次建立和UI重新渲染時 |
didUpdateWidget | n | 第一次建立和UI重新渲染時 |
deactivate | n | state物件將要移除時 |
dispose | 1 | state物件移除 |