在Widget銷毀之前將WebView的監(jiān)聽(tīng)和view銷毀掉。
為陜州等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及陜州網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為網(wǎng)站建設(shè)、做網(wǎng)站、陜州網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
flutter生命周期大體上可以分為三個(gè)階段:初始化、狀態(tài)變化、銷毀。
1、初始化階段
對(duì)應(yīng)執(zhí)行構(gòu)造方法和initState時(shí)候2、狀態(tài)變化階段
開(kāi)新的widget或者調(diào)用setState方法的時(shí)候
3、銷毀階段
deactivate和dispose
二、生命周期階段執(zhí)行的函數(shù)
1、initState調(diào)用次數(shù):1次
插入渲染樹(shù)時(shí)調(diào)用,只調(diào)用一次,widget創(chuàng)建執(zhí)行的第一個(gè)方法,這里可以做一些初始化工作,比如初始化State的變量。2、didChangeDependencies調(diào)用次數(shù):多次
初始化時(shí),在initState()之后立刻調(diào)用
當(dāng)依賴的InheritedWidgetrebuild,會(huì)觸發(fā)此接口被調(diào)用。實(shí)測(cè)在組件可見(jiàn)狀態(tài)變化的時(shí)候會(huì)調(diào)用
3、build調(diào)用次數(shù):多次初始化之后開(kāi)始繪制界面。setState觸發(fā)的時(shí)候會(huì)
4、didUpdateWidget調(diào)用次數(shù):多次組件狀態(tài)改變時(shí)候調(diào)用。
5、deactivate當(dāng)State對(duì)象從樹(shù)中被移除時(shí),會(huì)調(diào)用此回調(diào),會(huì)在dispose之前調(diào)用。頁(yè)面銷毀的時(shí)候會(huì)依次執(zhí)行:deactivatedispose
6、dispose調(diào)用次數(shù):1次當(dāng)State對(duì)象從樹(shù)中被永久移除時(shí)調(diào)用;通常在此回調(diào)中釋放資源。
7、reassemble在熱重載(hotreload)時(shí)會(huì)被調(diào)用,此回調(diào)在Release模式下永遠(yuǎn)不會(huì)被調(diào)用。
與iOS的ViewController、Android的Activity一樣,F(xiàn)lutter中的Widget也存在生命周期,并且通過(guò)State來(lái)提現(xiàn)。而App則是一個(gè)特殊的Widget,除了需要處理視圖顯示的各個(gè)階段,還需要應(yīng)對(duì)應(yīng)用從啟動(dòng)到退出所經(jīng)歷的各個(gè)狀態(tài)。
State的生命周期,指的是在用戶參與的情況查下,其關(guān)聯(lián)的Widget所經(jīng)歷的從創(chuàng)建到顯示再到更新最后到停止,直至銷毀的各個(gè)過(guò)程階段。
這些不同的階段涉及到的特定的任務(wù)處理,正確理解State的生命周期至關(guān)重要,State的生命周期流程圖圖,如下所示:
從圖中可以看到,State的生命周期可以分為3個(gè)階段:創(chuàng)建、更新、銷毀。下面將介紹每一個(gè)階段的具體流程
State初始化時(shí)會(huì)依次執(zhí)行:構(gòu)造方法 - initState - didChangeDependencies - build,隨后完成頁(yè)面渲染
Widget的狀態(tài)更新,主要由3個(gè)方法觸發(fā):setState、didChangeDependencies與didUpdateWidget。
一旦這三個(gè)方法被調(diào)用,F(xiàn)lutter就回銷毀舊的Widget,并調(diào)用build方法重建Widget
組件銷毀相對(duì)比較簡(jiǎn)單,組件被移除,或者頁(yè)面銷毀的時(shí)候,系統(tǒng)會(huì)調(diào)用deactivate和dispose這兩個(gè)方法來(lái)移除或銷毀組件
下面這張表格也可以幫助我們理解記憶這些調(diào)用實(shí)際
視圖的生命周期,定義了視圖的加載到構(gòu)建的全過(guò)程,其回調(diào)機(jī)制能夠確保我們可以更具視圖的狀態(tài)選擇合適的時(shí)間做恰當(dāng)?shù)氖虑?,而App的生命周期,則定義了App從啟動(dòng)到退出的全過(guò)程
在原生Android、iOS開(kāi)發(fā)中,有時(shí)我們需要再對(duì)應(yīng)的App生命周期事件中做相應(yīng)的處理,比如App從后臺(tái)進(jìn)入前臺(tái),從前臺(tái)退出后臺(tái),或者在UI繪制完成后做一些處理。
這樣的需求,在原生開(kāi)發(fā)中,可以通過(guò)重寫Activity、ViewController生命周期回調(diào)方法,或者是注冊(cè)應(yīng)用程序的相關(guān)通知來(lái)兼容App的生命周期并做相應(yīng)的處理。而在Flutter中,我們可以利用WidgetsBindingObserver類,來(lái)實(shí)現(xiàn)同樣的需求。
下面我們看看WidgetsBindingObserver中具體有哪些回調(diào)函數(shù):
didChangeAppLifecycleState回調(diào)函數(shù)中,有一個(gè)參數(shù)類型為AppLifecycleState的枚舉類型,這個(gè)枚舉類型是Flutter對(duì)App生命周期狀態(tài)的封裝,它的常用狀態(tài)包括:
可以將App切前后臺(tái),控制臺(tái)輸出的App狀態(tài),可以發(fā)現(xiàn):
我們可以通過(guò)下面的這張圖直觀的了解狀態(tài)切換過(guò)程
除了需要監(jiān)聽(tīng)App的生命周期回調(diào)做相應(yīng)處理外,根據(jù)不同的需求,我們需要再組件宣講之后做一些與顯示安全相關(guān)的操作,在iOS中,可以通過(guò)GCD的方法,讓操作在下一個(gè)RunLoop執(zhí)行,在Android中,可以通過(guò)View.post()插入消息隊(duì)列,來(lái)保證在組件渲染后進(jìn)行相關(guān)操作。在Flutter中實(shí)現(xiàn)同樣的需求會(huì)更簡(jiǎn)單:使用WidgetsBinding來(lái)實(shí)現(xiàn)即可
WidgetsBinding提供了單詞Frame繪制回調(diào)和實(shí)時(shí)Frame繪制回調(diào)兩種機(jī)制來(lái)滿足不同的需求場(chǎng)景:
生命周期是一個(gè)從創(chuàng)建到銷毀的過(guò)程,F(xiàn)lutter生命周期分為兩部分:
1.Widget的生命周期
2.APP的生命周期
1.StatelessWidget
對(duì)于StatelessWidget來(lái)說(shuō),生命周期只有build過(guò)程。build是用來(lái)創(chuàng)建Widget的,在每次頁(yè)面刷新時(shí)會(huì)調(diào)用build。
2.StatefulWidget
StatefulWidget的生命周期依次為:
createState是StatefulWidget來(lái)創(chuàng)建State的方法,只調(diào)用一次,
initState是StatefulWidget創(chuàng)建后調(diào)用的第一個(gè)方法,而且只執(zhí)行一次。在執(zhí)行initState時(shí),View沒(méi)有渲染,但是StatefulWidget 已經(jīng)被加載到渲染樹(shù)里了,這事的StatefulWidget的 mount 的值會(huì)變?yōu)閠rue,知道dispose才會(huì)變?yōu)閒alse.一般我們把初始化的一些操作都放在initState中。
didChangeDependencies會(huì)在initState后立即調(diào)用,之后只有當(dāng)StatefulWidget依賴的InheritedWidget發(fā)生變化之后,didChangeDependencies才會(huì)調(diào)用,所以didChangeDependencies可以調(diào)用多次。
build方法會(huì)在didChangeDeoendencies之后立即調(diào)用,在之后setState()刷新時(shí),會(huì)重新調(diào)用build繪制頁(yè)面,所以build方法可以調(diào)用多次。但一般不再build中創(chuàng)建除創(chuàng)建Widget的方法,否則會(huì)影響渲染效率。
addPostFrameCallback是StatefulWidget渲染結(jié)束之后的回調(diào),只會(huì)調(diào)用一次,一般是在initState里添加回調(diào):,
一般在dispose中做一些取消監(jiān)聽(tīng)、動(dòng)畫的操作,和initState相對(duì)使用。
AppLifecycleState就是App的生命周期,包含四個(gè):
Flutter跟安卓的Activity、iOS的ViewController一樣擁有自己的生命周期, Flutter中一切都是Widget,渲染方式有點(diǎn)像H5的DOM樹(shù)。
Flutter生命周期可以分為3個(gè)階段:
1、實(shí)例化組件并添加到樹(shù), 即Navigator.push;
2、狀態(tài)變化,即打開(kāi)新的widget或者依賴的上級(jí)widget發(fā)生變化;
3、從樹(shù)中移除, 即Navigator.pop。
在Flutter中Widget都是不可變的, 但實(shí)際上需要根據(jù)對(duì)應(yīng)的狀態(tài)刷新Widget。 從而產(chǎn)生了StatelessWidget和StatefulWdiget, StatefulWidget是由2個(gè)對(duì)象Widget和State組成的。
為什么將State和Widget分開(kāi)呢?
答案是性能, State管理狀態(tài)(可以理解為Controller),Widget是UI(即View)。 根據(jù)狀態(tài)變化每次生成Widget(即View)可以節(jié)省內(nèi)存,即不必每次創(chuàng)建狀態(tài)對(duì)象State。
構(gòu)造函數(shù):
同其它高級(jí)語(yǔ)言, 只執(zhí)行一次;
initState:
插入到渲染樹(shù)時(shí)調(diào)用,只執(zhí)行一次。(類似Android Fragment的onCreateView函數(shù))
didChangeDependencies:
1、在初始化initState后執(zhí)行; 2、顯示/關(guān)閉其它widget。 3、可執(zhí)行多次;
didUpdateWidget:
上級(jí)節(jié)點(diǎn)rebuild widget時(shí), 即上級(jí)組件狀態(tài)發(fā)生變化時(shí)會(huì)觸發(fā)子widget執(zhí)行didUpdateWidget;
deative:
有點(diǎn)像Android的onStop函數(shù), 在打開(kāi)新的Widget或回到這個(gè)widget時(shí)會(huì)執(zhí)行; 可執(zhí)行多次;
dispose:
類似于Android的onDestroy, 在執(zhí)行Navigator.pop后會(huì)調(diào)用該辦法, 表示組件已銷毀;
reassemble:
點(diǎn)擊閃電會(huì)執(zhí)行,只用于調(diào)試時(shí)的hot reload。 release版本不會(huì)執(zhí)行該函數(shù)。
常見(jiàn)業(yè)務(wù)場(chǎng)景:
Widget A打開(kāi)Widget B: Navigator.push(B)
B構(gòu)造函數(shù)---B initState---B didChangeDependencies---B build---A deactive---A didChangeDependencies.
Widget B退出: Navigator.pop
A deactive---A didChangeDependencies---A build---B deactive---B dispose
可以看出, Flutter打開(kāi)、關(guān)閉Widget時(shí)跟安卓、iOS的時(shí)序一樣, 都是先處理即將顯示的界面。
activity生命周期和Flutter對(duì)應(yīng)關(guān)系:
Flutter提供了WidgetsBindingObserver來(lái)監(jiān)聽(tīng)AppLifecycleState, 而AppLifecycleState有4種狀態(tài):
1、 resumed 界面可見(jiàn), 同安卓的onResume。
2、inactive界面退到后臺(tái)或彈出對(duì)話框情況下, 即失去了焦點(diǎn)但仍可以執(zhí)行drawframe回調(diào);同安卓的onPause;
3、paused應(yīng)用掛起,比如退到后臺(tái),失去了焦點(diǎn)且不會(huì)收到drawframe回調(diào);同安卓的onStop;
4、suspending, iOS中沒(méi)用,安卓里就是掛起,不會(huì)再執(zhí)行drawframe回調(diào);
下面是生命周期:
1、初次打開(kāi)widget時(shí),不執(zhí)行AppLifecycleState的回調(diào);
2、按home鍵或Power鍵, AppLifecycleState inactive----AppLifecycleState pause
3、從后臺(tái)到前臺(tái):AppLifecycleState inactive---ApplifecycleState resumed
4、back鍵退出應(yīng)用: AppLifecycleState inactive---AppLifecycleState paused
可以使用 SingleChildScrollView 包裹布局
這里還需要了解一個(gè) Scaffold 中的一個(gè)屬性 resizeToAvoidBottomInset
官方文檔給出的解釋就是處理鍵盤遮擋問(wèn)題,默認(rèn)是 true,如果不希望頂起需要設(shè)置為 false。
在 sdk 低版本的時(shí)候是使用 resizeToAvoidBottomPadding 需要將其設(shè)置為 false,現(xiàn)在已經(jīng)棄用。但網(wǎng)上很多文章還沒(méi)有改正,仍然用的 resizeToAvoidBottomPadding。
分兩種情況
一種是使用系統(tǒng)的返回鍵,比如 android 底部導(dǎo)航自帶的返回,
另一種是使用導(dǎo)航欄自定義的返回鍵
第一種情況需要在頁(yè)面根布局使用 WillPopScope 在 onWillPop 中攔截返回處理。
原理都是通過(guò)判斷輸入框是否獲取了焦點(diǎn)
當(dāng)?shù)撞坑泄潭ǖ慕M件,比如提交按鈕,我們?cè)阪I盤彈起的時(shí)候希望按鈕貼著鍵盤頂部固定,但是中間滾動(dòng)視圖可以自由滾動(dòng)
可以在 SingleChildScrollView 外部再使用 Stack 包裹,懸浮按鈕使用 Positioned 定位,
還要??注意要給滾動(dòng)組件底部留出距離防遮擋,同時(shí)還有動(dòng)態(tài)加上 bottomBar 的高度,因?yàn)樵?iphoneX 以上的手機(jī),會(huì)有個(gè)虛擬按鍵,如果不加上該按鍵高度,同樣會(huì)被遮擋
高度獲取方法: MediaQuery.of(context).padding.bottom
在 showDialog 布局中使用 Scaffold 包裹,不要忘了將 backgroundColor 設(shè)為透明。
如果彈窗過(guò)高,還是需要將高度固定,然后使用 SingleChildScrollView ,彈窗中同樣也可以在執(zhí)行關(guān)閉的時(shí)候攔截,判斷鍵盤是否彈起,如果彈起則要先關(guān)閉鍵盤。
給所有輸入框綁定 FoucusNode
在 maxLines=1 的情況下,輸入框不支持換行,換行按鈕會(huì)變成 done
監(jiān)聽(tīng) onEditingComplete 方法
根布局使用 GestureDetector 或者 InkWell 包裹,點(diǎn)擊的時(shí)候收起鍵盤。
最后要記得銷毀