State 生命週期
State 的生命週期可以分為 3 個階段:建立(插入檢視樹)、更新(在檢視樹中存在)、銷燬(從檢視樹中移除)。建立
State 初始化時會依次執行 :構造方法 -> initState -> didChangeDependencies -> build,隨後完成頁面渲染。
- 構造方法是 State 生命週期的起點,Flutter 會通過呼叫 StatefulWidget.createState() 來建立一個 State。我們可以通過構造方法,來接收父 Widget 傳遞的初始化 UI 配置資料。這些配置資料,決定了 Widget 最初的呈現效果。
- initState,會在 State 物件被插入檢視樹的時候呼叫。這個函式在 State 的生命週期中只會被呼叫一次,所以我們可以在這裡做一些初始化工作,比如為狀態變數設定預設值。
- didChangeDependencies 則用來專門處理 State 物件依賴關係變化,會在 initState() 呼叫結束後,被 Flutter 呼叫。
- build,作用是構建檢視。經過以上步驟,Framework 認為 State 已經準備好了,於是呼叫 build。我們需要在這個函式中,根據父 Widget 傳遞過來的初始化配置資料,以及 State 的當前狀態,建立一個 Widget 然後返回。
更新
Widget 的狀態更新,主要由 3 個方法觸發:setState、didchangeDependencies 與 didUpdateWidget。
- setState:我們最熟悉的方法之一。當狀態資料發生變化時,我們總是通過呼叫這個方法告訴 Flutter:“我這兒的資料變啦,請使用更新後的資料重建 UI!”
- didChangeDependencies:State 物件的依賴關係發生變化後,Flutter 會回撥這個方法,隨後觸發元件構建。哪些情況下 State 物件的依賴關係會發生變化呢?典型的場景是,系統語言 Locale 或應用主題改變時,系統會通知 State 執行 didChangeDependencies 回撥方法。
- didUpdateWidget:當 Widget 的配置發生變化時,比如,父 Widget 觸發重建(即父 Widget 的狀態發生變化時),熱過載時,系統會呼叫這個函式。
一旦這三個方法被呼叫,Flutter 隨後就會銷燬老 Widget,並呼叫 build 方法重建 Widget。
銷燬
比如元件被移除,或是頁面銷燬的時候,系統會呼叫 deactivate 和 dispose 這兩個方法,來移除或銷燬元件。
- 當元件的可見狀態發生變化時,deactivate 函式會被呼叫,這時 State 會被暫時從檢視樹中移除。值得注意的是,頁面切換時,由於 State 物件在檢視樹中的位置發生了變化,需要先暫時移除後再重新新增,重新觸發元件構建,因此這個函式也會被呼叫。
- 當 State 被永久地從檢視樹中移除時,Flutter 會呼叫 dispose 函式。而一旦到這個階段,元件就要被銷燬了,所以我們可以在這裡進行最終的資源釋放、移除監聽、清理環境,等等。
App 生命週期
在原生開發中,我們可以通過重寫 Activity、ViewController 生命週期回撥方法,或是註冊應用程式的相關通知,來監聽 App 的生命週期並做相應的處理。而在 Flutter 中,我們可以利用 WidgetsBindingObserver 類,來實現同樣的需求。
abstract class WidgetsBindingObserver {
//頁面pop
Future<bool> didPopRoute() => Future<bool>.value(false);
//頁面push
Future<bool> didPushRoute(String route) => Future<bool>.value(false);
//系統視窗相關改變回撥,如旋轉
void didChangeMetrics() { }
//文字縮放係數變化
void didChangeTextScaleFactor() { }
//系統亮度變化
void didChangePlatformBrightness() { }
//本地化語言變化
void didChangeLocales(List<Locale> locale) { }
//App生命週期變化
void didChangeAppLifecycleState(AppLifecycleState state) { }
//記憶體警告回撥
void didHaveMemoryPressure() { }
//Accessibility相關特性回撥
void didChangeAccessibilityFeatures() {}
}
複製程式碼
生命週期回撥
- resumed:可見的,並能響應使用者的輸入。
- inactive:處在不活動狀態,無法處理使用者響應。
- paused:不可見並不能響應使用者的輸入,但是在後臺繼續活動中。
幀繪製回撥
在元件渲染之後做一些與顯示安全相關的操作。
在 iOS 開發中,我們可以通過 dispatch_async(dispatch_get_main_queue(),^{…}) 方法,讓操作在下一個 RunLoop 執行;
在 Android 開發中,我們可以通過 View.post() 插入訊息佇列,來保證在元件渲染後進行相關操作。
- 單次 Frame 繪製回撥,通過 addPostFrameCallback 實現。它會在當前 Frame 繪製完成後進行進行回撥,並且只會回撥一次,如果要再次監聽則需要再設定一次。
WidgetsBinding.instance.addPostFrameCallback((_){
print("單次Frame繪製回撥");//只回撥一次
});
複製程式碼
- 實時 Frame 繪製回撥,則通過 addPersistentFrameCallback 實現。這個函式會在每次繪製 Frame 結束後進行回撥,可以用做 FPS 監測。
WidgetsBinding.instance.addPersistentFrameCallback((_){
print("實時Frame繪製回撥");//每幀都回撥
});
複製程式碼
總結
State的變化,則會觸發build,重建Widget。比如Widget A開啟新的Widget B,Widget A的State發生變化。