Flutter路由棧和生命週期解析

前言

年前因爲業務調整開始接觸學習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跳轉到screen2spa

Navigator.pushNamed(context, '/screen2')
複製代碼

退出路由pop3d

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等,就不贅述了。

取消導航Header的返回鍵

AppBar(automaticallyImplyLeading: false)
複製代碼

WillPopScope取消Android物理返回鍵

這個方法也能夠取消iOS默認左右滑動切換路由。

Widget build(BuildContext context) {
    return WillPopScope(
        onWillPop: () async {
          return false;
        },
        child: Scaffold(
            // Your Code
        )
    );
}
複製代碼
相關文章
相關標籤/搜索