年前因爲業務調整開始接觸學習Flutter,本身重寫了業務線的功能型App。其中遇到很多坑,此次主要總結下路由棧以及生命週期的內容,後續再慢慢補充~bash
路由(Routes)是什麼?路由是屏幕或應用程序頁面的抽象。async
Flutter 使咱們可以優雅地管理路由主要依賴的是 Navigator(導航器)類。這是一個用於管理一組具備某種進出規則的頁面的 Widget,也就是說用它咱們可以實現各個頁面間有規律的切換。而這裏的規則即是在其內部維護的一個「 路由棧」。ide
在通常應用中,咱們用的最多的仍是命名路由,它是將應用中須要訪問的每一個頁面命名爲不重複的字符串,咱們即可以經過這個字符串來將該頁面實例推動路由。函數
例如:學習
new MaterialApp(
home: new Screen1(),
routes: <String, WidgetBuilder> {
'/screen1': (BuildContext context) => new Screen1(),
'/screen2' : (BuildContext context) => new Screen2(),
'/screen3' : (BuildContext context) => new Screen3(),
'/screen4' : (BuildContext context) => new Screen4()
},
)
複製代碼
Navigator維護了一個堆棧,來保存路由跳轉的狀態。ui
由screen1
跳轉到screen2
spa
Navigator.pushNamed(context, '/screen2')
複製代碼
退出路由pop
3d
Navigator.pop()
code
切勿用pushNamed
替代pop
,否則就會出現下面的狀況了。orm
簡單地聊完路由棧,接下來介紹 StatefulWidget
一系列的生命週期。
上圖就是 State 的生命週期圖。
StatefulWidget.createState()
Framework 經過調用 StatefulWidget.createState() 來建立一個 State。
initState()
新建立的 State 會和一個 BuildContext 產生關聯,此時認爲 State 已經被安裝好了,initState() 函數將會被調用。一般,咱們能夠重寫這個函數,進行初始化操做。
didChangeDependencies()
在 initState() 調用結束後,這個函數會被調用。事實上,當 State 對象的依賴關係發生變化時,這個函數總會被 Framework 調用。
build()
通過以上步驟,系統認爲一個 State 已經準備好了,就會調用 build() 來構建視圖。咱們須要在這個函數中,返回一個 Widget。
deactivate()
當 State 被暫時從視圖樹中移除時,會調用這個函數。頁面切換時,也會調用它,由於此時 State 在視圖樹中的位置發生了變化,須要先暫時移除後添加。⚠️注意,重寫的時候必需要調用 super.deactivate()。
dispose()
當 State 被永久的從視圖樹中移除,Framework 會調用該函數。在銷燬前觸發,咱們能夠在這裏進行最終的資源釋放。在調用這個函數以前,總會先調用 deactivate()。⚠️注意,重寫的時候必需要調用 super.dispose()
didUpdateWidget(covariant T oldWidget)
當 widget 的配置發生變化時,會調用這個函數。好比,Hot-reload 的時候就會調用這個函數。這個函數調用後,會調用 build()。
setState()
當我須要更新 State 的視圖時,須要手動調用這個函數,它會觸發 build() 。
通常狀況下咱們用的最多的是initState
,build
,deactivate
,dispose
,setState
。接下來也主要講initState
以及dispose
在路由跳轉過程當中的觸發條件。
initState
,deactivate
,dispose
一開始咱們是這麼寫的
@override
void initState() {
super.initState();
print('------initstate--------');
}
void deactivate() {
super.deactivate();
print('-----deactivate----');
}
void dispose() {
super.dispose();
print('----dispose--------');
}
複製代碼
當咱們經過pushNamed
跳轉到其餘路由,發現deactivate
觸發了,可是dispose
並無觸發,而且再次經過pushNamed
回到本頁的時候,initstate
也並無再次執行。
寫多了Vue
單頁面應用的同窗,應該知道這其實很讓人困擾。咱們不少時候須要像Vue
同樣,在created
的時候初始化數據,在beforeDestroy
的時候移除頁面一些監聽事件或者銷燬定時器,防止內存泄露。
讓咱們回到生命週期說明那裏:
deactivate()
當 State 被暫時從視圖樹中移除時,會調用這個函數。
dispose()
當 State 被永久的從視圖樹中移除,Framework 會調用該函數。
此時是否是恍然大悟!pushNamed
只是暫時把視圖移除了,並無完全移除,因此致使了一些奇怪的問題(前提是你跟我同樣,業務上須要控制頁面的初始化和銷燬)
那怎麼辦。此時popAndPushNamed
閃亮登場!用它替代pushNamed
,你就會發現該觸發的事件都觸發了~
popAndPushNamed
將當前路由彈出並跳轉到新的路由,完全移除舊路由。
還有相似的方法pushReplacementNamed
,pushNamedAndRemoveUntil
等,就不贅述了。
AppBar(automaticallyImplyLeading: false)
複製代碼
WillPopScope
取消Android物理返回鍵這個方法也能夠取消iOS默認左右滑動切換路由。
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
return false;
},
child: Scaffold(
// Your Code
)
);
}
複製代碼