flutter中的生命周期函数
前言:生命周期是一個組件加載到卸載的整個周期,熟悉生命周期可以讓我們在合適的時機做該做的事情,
flutter中的State生命周期和android以及React Native的生命周期類似。
先看一張生命周期的流程圖:
大致可以分為3個階段:
初始化
狀態變化
組件移除
初始化
State初始化時會依次執行 : 構造函數 > initState > didChangeDependencies > Widget build , 此時頁面加載完成。
然后我們看一下每個函數的意義:
構造函數
調用次數:1次
這個函數嚴格意義上來講不屬于生命周期的一部分,因為這個時候State的widget屬性為空,無法在構造函數中訪問widget的屬性 。但是構造函數必然是要第一個調用的。可以在這一部分接收前一個頁面傳遞過來的數據。
initState
Called when this object is inserted into the tree.
調用次數:1次
當插入渲染樹的時候調用,這個函數在生命周期中只調用一次。這里可以做一些初始化工作,比如初始化State的變量。
didChangeDependencies
Called when a dependency of this [State] object changes.
初始化時,在initState()之后立刻調用
當依賴的InheritedWidget rebuild,會觸發此接口被調用
這個函數會緊跟在initState之后調用,并且可以調用BuildContext.inheritFromWidgetOfExactType,那么BuildContext.inheritFromWidgetOfExactType的使用場景是什么呢?最經典的應用場景是
new DefaultTabController(length: 3, child: new TabBar(
tabs: [ "主頁","訂單","我的" ]
.map( (data)=>new Text(data) ).toList(),
TabBar本來需要定義一個TabController,但是在外面套一層DefaultTabController就不需要定義TabContrller了,看下源碼:
@override
void didChangeDependencies() {
super.didChangeDependencies();
_updateTabController();
_initIndicatorPainter();
}
void _updateTabController() {
final TabController newController = widget.controller ?? DefaultTabController.of(context);
...
}
注意到這里DefaultTabController.of(context)
static TabController of(BuildContext context) {
final _TabControllerScope scope = context.inheritFromWidgetOfExactType(_TabControllerScope);
return scope?.controller;
}
實際上就是調用BuildContext.inheritFromWidgetOfExactType,也就說在didChangeDependencies中,可以跨組件拿到數據。
#運行時
build
調用次數:多次
初始化之后開始繪制界面,當setState觸發的時候會再次被調用
didUpdateWidget
Called whenever the widget configuration changes.
祖先節點rebuild widget時調用 .當組件的狀態改變的時候就會調用didUpdateWidget.
理論上setState的時候會調用,但我實際操作的時候發現只是做setState的操作的時候沒有調用這個方法。而在我改變代碼hot reload時候會調用 didUpdateWidget 并執行 build…
實際上這里flutter框架會創建一個新的Widget,綁定本State,并在這個函數中傳遞老的Widget。
這個函數一般用于比較新、老Widget,看看哪些屬性改變了,并對State做一些調整。
需要注意的是,涉及到controller的變更,需要在這個函數中移除老的controller的監聽,并創建新controller的監聽。
組件移除
組件移除,例如頁面銷毀的時候會依次執行:deactivate > dispose
deactivate
Called when this object is removed from the tree.
在dispose之前,會調用這個函數。實測在組件可見狀態變化的時候會調用,當組件卸載時也會先一步dispose調用。
dispose
Called when this object is removed from the tree permanently.
調用次數:1次
一旦到這個階段,組件就要被銷毀了,這個函數一般會移除監聽,清理環境。
##reassemble
hot reload調用
| 名稱 | 狀態 |
|---|---|
| initState | 插入渲染樹時調用,只調用一次 |
| didChangeDependencies | state依賴的對象發生變化時調用 |
| didUpdateWidget | 組件狀態改變時候調用,可能會調用多次 |
| build | 構建Widget時調用 |
| deactivate | 當移除渲染樹的時候調用 |
| dispose | 組件即將銷毀時調用 |
實際場景
假設我們從A頁面跳轉到B頁面, 那么A,B頁面的生命周期會是怎樣的呢?
B頁面進入初始化狀態,依次執行4個函數:構造函數 > initState > didChangeDependencies > Widget build , 此時頁面加載完成,進入運行態。
此時A頁面依次執行deactivate > build函數。注意 此時A頁面并未卸載。
然后我們假設B頁面只有一個按鈕,點擊B頁面中的按鈕,改變按鈕的文字,會執行widget的build方法 ,(理論上也應該執行didUpdateWidget,但我這里沒有)。
這時,我們點擊返回鍵從B頁面返回到A頁面。
A頁面重新顯示,B頁面開始卸載。
那么A先執行deactivate > build , 然后B頁面依次執行:deactivate > dispose 。
此時A頁面進入運行態,B頁面移除。
本次示例B頁面代碼:
import 'package:flutter/material.dart';
class NewsDetailPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => NewsDetailState();
}
class NewsDetailState extends State<NewsDetailPage> {
int text = 1;
NewsDetailState() {
print('構造函數');
}
@override
void initState() {
print('init state');
super.initState();
}
@override
void didChangeDependencies() {
print('didChangeDependencies');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('widget build');
return Scaffold(
body: Center(
child: _loading(),
),
appBar: AppBar(
title: Text('咨詢詳情'),
),
);
}
@override
void didUpdateWidget(NewsDetailPage oldWidget) {
print('組件狀態改變:didUpdateWidget');
super.didUpdateWidget(oldWidget);
}
@override
void deactivate() {
print('移除時:deactivate');
super.deactivate();
}
@override
void dispose() {
print('移除時:dispose');
super.dispose();
}
//預加載布局
Widget _loading() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(
strokeWidth: 1.0,
),
Container(
child: Text("正在加載"),
margin: EdgeInsets.only(top: 10.0),
)
],
);
}
}
Tips:
下面內容來自咸魚技術團隊.
當ListView中的item滾動出可顯示區域的時候,item會被從樹中remove掉,此item子樹中所有的state都會被dispose,state記錄的數據都會銷毀,item滾動回可顯示區域時,會重新創建全新的state、element、renderobject
使用hot reload功能時,要特別注意state實例是沒有重新創建的,如果該state中存在一下復雜的資源更新需要重新加載才能生效,那么需要在reassemble()添加處理,不然當你使用hot reload時候可能會出現一些意想不到的結果,例如,要將顯示本地文件的內容到屏幕上,當你開發過程中,替換了文件中的內容,但是hot reload沒有觸發重新讀取文件內容,頁面顯示還是原來的舊內容.
didChangeDependencies有兩種情況會被調用。
創建時候在initState 之后被調用
在依賴的InheritedWidget發生變化的時候會被調用
正常的退出流程中會執行deactivate然后執行dispose。但是也會出現deactivate以后不執行dispose,直接加入樹中的另一個節點的情況。
這里的狀態改變包括兩種可能:1.通過setState內容改變 2.父節點的state狀態改變,導致孩子節點的同步變化。
App生命周期
需要指出的是如果想要知道App的生命周期,那么需要通過WidgetsBindingObserver的didChangeAppLifecycleState 來獲取。通過該接口可以獲取是生命周期在AppLifecycleState類中。常用狀態包含如下幾個:
| 名稱 | 狀態 |
|---|---|
| resumed | 可見并能響應用戶的輸入 |
| inactive | 處在并不活動狀態,無法處理用戶響應 |
| paused | 不可見并不能響應用戶的輸入,但是在后臺繼續活動中 |
一個實際場景中的例子:
在不考慮suspending的情況下:從后臺切入前臺生命周期變化如下: AppLifecycleState.inactive->AppLifecycleState.resumed;
從前臺壓后臺生命周期變化如下: AppLifecycleState.inactive->AppLifecycleState.paused;
原文:https://blog.csdn.net/u011272795/article/details/82695920
總結
以上是生活随笔為你收集整理的flutter中的生命周期函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再学 GDI+[60]: TGPGrap
- 下一篇: JavaScript 图片滑动切换效果