一.典型情況下的生命周期
- onCreat: 表示Activity正在被創(chuàng)。再次方法中,我們可以做一些初始化工作,例如調(diào)用setContentView去加載界面布局資源、初始化Activity所需數(shù)據(jù)等。
- onRestart:表示Activity正在重新啟動(dòng)。一般情況下,當(dāng)Activity從不可見(jiàn)變?yōu)榭梢?jiàn)狀態(tài)時(shí),此方法就會(huì)被調(diào)用。這種情況是由于用戶操作導(dǎo)致,一般是由于用戶點(diǎn)擊的home鍵或點(diǎn)開(kāi)了一個(gè)新的Activity,這時(shí)當(dāng)前Activity就會(huì)暫停,就是onPause和onStop被執(zhí)行了,接著用戶又回到這個(gè)Activity,就會(huì)出現(xiàn)該情況。
- onStart:表示Activity正在被啟動(dòng),即將開(kāi)始。這時(shí)的Activity已經(jīng)可見(jiàn)了,但沒(méi)有出現(xiàn)在前臺(tái),無(wú)法和用戶交互。
- onResume:表示Activity已經(jīng)可見(jiàn),并出現(xiàn)在前臺(tái)開(kāi)始活動(dòng)。onStart和onResume都表示Activity已經(jīng)可見(jiàn),區(qū)別是,onStart的時(shí)候Activity在后臺(tái),而onResume的時(shí)候Activity位于前臺(tái)。
- onPause:表示Activity正在停止。此時(shí)可以做一些數(shù)據(jù)儲(chǔ)存,停止動(dòng)畫等操作,但注意不能太耗時(shí),因?yàn)檫@樣會(huì)影響新的Activity顯示,因?yàn)閛nPause必須先執(zhí)行完,新的Activity的onResume才會(huì)執(zhí)行。正常情況下,緊接著onStop就會(huì)被調(diào)用,在特殊情況下,如果此時(shí)快速回到當(dāng)前Activity,那么onRestart會(huì)被調(diào)用,這是一種極端情況,用戶操作很難重現(xiàn)。
- onStop:表示Activity即將停止,可以做一些稍微重量級(jí)的工作,但同樣不能太耗時(shí)。onStop和onPause的區(qū)別是,onPause的時(shí)候,Activity在前臺(tái),還能與用戶交互,而onStop的時(shí)候,Activity就位于后臺(tái)了。
-
onDestory:表示Activity即將被銷毀。我們可以在這個(gè)做一些回收工作和最終的資源釋放。
Activity生命周期切換過(guò)程.jpg
針對(duì)上圖,附加說(shuō)明幾點(diǎn):
(1)用戶打開(kāi)新的Activity或點(diǎn)擊Home鍵時(shí),回調(diào)如下:onPause -> onStop。這里有一特殊情況,若新的Activity采用了透明主題,則當(dāng)前Activity不會(huì)調(diào)用onStop。
(2)當(dāng)用戶再次回到Activity時(shí),回調(diào)如下:onRestart -> onStart -> onResume。
(3)當(dāng)用戶點(diǎn)擊back鍵時(shí),回調(diào)如下:onPause -> onStop -> onDestroy。
(4)從整個(gè)生命周期來(lái)說(shuō),onCreate和onDestroy配對(duì),標(biāo)識(shí)Activity的創(chuàng)建與銷毀,且只能調(diào)用一次;從Activity是否可見(jiàn)來(lái)看,onStart和onStop是配對(duì)的,這兩個(gè)方法會(huì)隨用戶操作而多次被調(diào)用;從Activity是否位于前臺(tái)來(lái)說(shuō),onResume和onPause是配對(duì)的,這兩個(gè)方法也會(huì)隨用戶操作而多次被調(diào)用。
二.異常情況下的生命周期
情況1:資源相關(guān)的系統(tǒng)配置發(fā)生改變導(dǎo)致Activity被殺死并重新創(chuàng)建
舉例來(lái)說(shuō),當(dāng)前Activity處于豎屏狀態(tài),若突然旋轉(zhuǎn)屏幕,由于配置發(fā)生改變,默認(rèn)情況下,Activity就會(huì)被銷毀并重新創(chuàng)建。這時(shí),如果我們不對(duì)Activity做特殊處理,那么Activity的生命周期就會(huì)如下圖所示。

(1)當(dāng)系統(tǒng)配置發(fā)生改變后,Activity會(huì)被銷毀,其onPause、onStop、onDestroy會(huì)被調(diào)用,由于Activity是在異常情況下終止,系統(tǒng)會(huì)調(diào)用onSaveInstanceState來(lái)保存當(dāng)前Activity的狀態(tài),此方法的調(diào)用時(shí)機(jī)是在onStop之前,它和onPause沒(méi)有既定的時(shí)序關(guān)系。需要強(qiáng)調(diào)的是,這個(gè)方法在正常情況下系統(tǒng)不會(huì)調(diào)用。
(2)當(dāng)Activity被重建時(shí),系統(tǒng)會(huì)調(diào)用onRestoreInstanceState,并把Activity銷毀時(shí)onSaveInstanceState方法所保存的bundle對(duì)象作為參數(shù)傳遞給onRestoreInstanceState和onCreate方法。因此,我們可以從onRestoreInstanceState和onCreate方法來(lái)判斷Activity是否被重建。如果被重建,我們則可以取出之前保存的數(shù)據(jù)并恢復(fù)。從時(shí)序上看,onRestoreInstanceState是在onStart之后被調(diào)用。
(3)在onSaveInstanceState和onRestoreInstanceState方法中,系統(tǒng)會(huì)自動(dòng)為我們做一定的恢復(fù)工作。例如,Activity在異常情況下重新創(chuàng)建時(shí),系統(tǒng)會(huì)默認(rèn)保存當(dāng)前Activity的視圖結(jié)構(gòu),并在Activity重啟后恢復(fù)這些數(shù)據(jù),比如文本框中輸入的數(shù)據(jù),ListView滾動(dòng)位置等。具體對(duì)某一特定View系統(tǒng)能恢復(fù)那些數(shù)據(jù),可以查看View的源碼(和Activity一樣,每個(gè)View都有onSaveInstanceState和onRestoreInstanceState方法)。
(4)關(guān)于保存和恢復(fù)View層次機(jī)構(gòu),系統(tǒng)工作流程如下:首先Activity意外終止,Activity會(huì)調(diào)用onSaveInstanceState去保存數(shù)據(jù),然后Activity會(huì)委托Window來(lái)保存數(shù)據(jù),接著Window會(huì)委托頂層容器去保存數(shù)據(jù)。頂層容器是個(gè)ViewGroup,一般來(lái)說(shuō)很可能是個(gè)DecorView。最后,頂層容器再一一通知子元素來(lái)保存數(shù)據(jù),這樣整個(gè)數(shù)據(jù)保存過(guò)程就結(jié)束了??梢钥闯?,這是一種典型的委托思想,上層委托下層,父容器委托子元素。這種思想在Android中有很多的應(yīng)用,比如View的繪制過(guò)程、時(shí)間分發(fā)等等都采用了類似思想。
情況2:資源內(nèi)存不足導(dǎo)致低優(yōu)先級(jí)Activity被殺死
該情況我們不好模擬,但其儲(chǔ)存模式和情況1完全一致。Activity的優(yōu)先級(jí)從高到低,可分為如下三種:
(1)前臺(tái)Activity——正在和用戶交互的Activity,這種優(yōu)先級(jí)最高。
(2)可見(jiàn)但非前臺(tái)Activity——例如Activity彈出了一個(gè)對(duì)話框,導(dǎo)致Activity可見(jiàn)但位于后臺(tái)無(wú)法和用戶交互,比如執(zhí)行了onPause,優(yōu)先級(jí)次之。
(3)后臺(tái)Activity——已經(jīng)被暫停的Activity,比如執(zhí)行了onStop,這種優(yōu)先級(jí)最低。
當(dāng)系統(tǒng)內(nèi)存不足時(shí),系統(tǒng)會(huì)按照上述優(yōu)先級(jí)去殺死目標(biāo)Activity所在進(jìn)程,并后續(xù)通過(guò)onSaveInstanceState和onRestoreInstanceState方法來(lái)儲(chǔ)存和恢復(fù)數(shù)據(jù)。若一個(gè)進(jìn)程中沒(méi)有四大組件在執(zhí)行,那么這個(gè)進(jìn)程將很快被殺死,較好的方法是將后臺(tái)工作放入Service中,從而保證進(jìn)程有一定優(yōu)先級(jí),這樣就不會(huì)輕易被系統(tǒng)殺死了。
那么當(dāng)系統(tǒng)配置發(fā)生改變后,什么方法才能讓Activity不被重新創(chuàng)建呢?方法是這樣的,我們可以給Activity指定configChanges屬性。例如不想讓Activity在屏幕旋轉(zhuǎn)時(shí)重建,我們就可以給configChanges屬性添加orientation這個(gè)值,如下。
android:configChanges="orientation"
若我們想指定多個(gè)值,可以使用“|”連接起來(lái),如下。
android:configChanges="orientation|keyboardHidden"
系統(tǒng)配置中所含項(xiàng)目有很多,下面介紹了每個(gè)項(xiàng)目的含義。
- “mcc“ 移動(dòng)國(guó)家號(hào)碼,由三位數(shù)字組成,每個(gè)國(guó)家都有自己獨(dú)立的MCC,可以識(shí)別手機(jī)用戶所屬國(guó)家。
- “mnc“ 移動(dòng)網(wǎng)號(hào),在一個(gè)國(guó)家或者地區(qū)中,用于區(qū)分手機(jī)用戶的服務(wù)商。
- “l(fā)ocale“ 所在地區(qū)發(fā)生變化。
- “touchscreen“ 觸摸屏已經(jīng)改變。(這不應(yīng)該常發(fā)生。)
- “keyboard“ 鍵盤模式發(fā)生變化,例如:用戶接入外部鍵盤輸入。
- “keyboardHidden“ 用戶打開(kāi)手機(jī)硬件鍵盤。
- “navigation“ 導(dǎo)航型發(fā)生了變化。(這不應(yīng)該常發(fā)生。)
- “orientation“ 設(shè)備旋轉(zhuǎn),橫向顯示和豎向顯示模式切換。
- “fontScale“ 全局字體大小縮放發(fā)生改變。
- “screenSize” 屏幕尺寸信息發(fā)生改變,和屏幕方向無(wú)關(guān)僅表示屏幕物理尺寸改變。當(dāng)minSdkVersion一個(gè)小于等于13,為防止旋轉(zhuǎn)屏幕時(shí)Activity重啟,除了“orientation“,我們還要加上“screenSize”。
我們常用的時(shí)local,orientation,keyboardHidden這三個(gè)選項(xiàng)。
三.Activity的啟動(dòng)模式
為什么需要啟動(dòng)模式,因?yàn)樵谀J(rèn)情況下,當(dāng)我們多次啟動(dòng)同一Activity時(shí),系統(tǒng)會(huì)創(chuàng)建多個(gè)實(shí)例并把它們一一入棧,而當(dāng)我們點(diǎn)擊back鍵時(shí),這些Activity會(huì)一一回退。任務(wù)棧是一種“后進(jìn)先出”的棧結(jié)構(gòu),每按一下back鍵就會(huì)有一個(gè)Activity出棧,直到棧空,系統(tǒng)會(huì)回收這個(gè)任務(wù)棧。上述是在Activity為默認(rèn)啟動(dòng)模式時(shí)會(huì)出現(xiàn)的情況。
目前Activity有四種啟動(dòng)模式:standard、singleTop、singleTask、singleInstance。
1.Standard
標(biāo)準(zhǔn)模式。夜視系統(tǒng)的默認(rèn)模式。每次啟動(dòng)一個(gè)Activity都會(huì)重新創(chuàng)建一個(gè)實(shí)例,無(wú)論該Activity是否已經(jīng)存在。被創(chuàng)建的實(shí)例的onCreate,onStart,onResume都會(huì)被調(diào)用。如果Activity A啟動(dòng)Activity B(B為標(biāo)準(zhǔn)模式),則B就會(huì)進(jìn)入A所在的任務(wù)棧中。
2.singleTop
棧頂復(fù)用模式。在此種模式下,如果新Activity已經(jīng)位于任務(wù)棧棧頂,那么此Activity不會(huì)被重新創(chuàng)建,同時(shí)它的onNewIntent方法會(huì)被回調(diào),通過(guò)此方法的參數(shù)我們能取出當(dāng)前請(qǐng)求的信息。如果新Activity已經(jīng)存在但不位于棧頂,那么新Activity仍然會(huì)被重新創(chuàng)建。
3.singleTask
棧內(nèi)復(fù)用模式。這是一種單實(shí)例模式,在此模式下,只要Activity存在于一個(gè)棧中,那么多次啟動(dòng)這個(gè)Activity都不會(huì)被重新創(chuàng)建實(shí)例。下面我通過(guò)幾個(gè)例子來(lái)更詳細(xì)講解singleTask的含義。(下面的Aty為Activity簡(jiǎn)稱)
- 若當(dāng)前S1棧內(nèi)的情況為ABC,這時(shí)Activity D以singleTask模式請(qǐng)求啟動(dòng),它需要的任務(wù)棧為S2。由于S2與實(shí)例D均不存在,系統(tǒng)會(huì)先創(chuàng)建任務(wù)棧S2,再創(chuàng)建D的實(shí)例并入棧到S2內(nèi)。(無(wú)棧,無(wú)Aty,先建棧,再建Aty并入棧)
- 若前面的情況相同,這時(shí)這時(shí)Activity D需要的任務(wù)棧為S1。由于S1已存在。系統(tǒng)會(huì)創(chuàng)建D的實(shí)例并入棧到S1內(nèi)。(有棧,無(wú)Aty,建Aty并入棧)
- 若S1內(nèi)仍未ABC,這時(shí)Activity B以singleTask模式請(qǐng)求啟動(dòng),它需要的任務(wù)棧為S1。由于S1與實(shí)例B均存在,此時(shí)B不會(huì)被重建,系統(tǒng)會(huì)把B切換到棧頂位置并調(diào)用其onNewIntent方法,同時(shí)由于singleTask默認(rèn)具有clearTop效果,會(huì)導(dǎo)致棧內(nèi)B上面的Activity全部出戰(zhàn)。于是最終S1內(nèi)情況為BC。(有棧,有Aty,將A置頂且Aty以上所有Aty全部出棧)
- singleTask啟動(dòng)模式中,Activity所需任務(wù)棧如何來(lái)制定呢?通過(guò)參數(shù):TaskAffinity,可以翻譯為任務(wù)相關(guān)性。這個(gè)參數(shù)可以標(biāo)識(shí)Activity所需任務(wù)棧名字,默認(rèn)情況下,所有Activity所需的任務(wù)棧名字為應(yīng)用的包名。當(dāng)然,我們也可以自己指定,指定的屬性值必須不能與包名一樣,否則相當(dāng)于沒(méi)指定。TaskAffinity主要和singleTask啟動(dòng)模式或allowTaskReparenting屬性配對(duì)使用,在其他情況下無(wú)意義。
①TaskAffinity和singleTask配對(duì)使用,Activity會(huì)運(yùn)行在TaskAffinity指定的任務(wù)棧中。
②TaskAffinity和allowTaskReparenting結(jié)合時(shí),情況較復(fù)雜,有奇效。當(dāng)A應(yīng)用啟動(dòng)了B應(yīng)用的某個(gè)Activity后,這時(shí)Activity會(huì)進(jìn)入A應(yīng)用任務(wù)棧中,若此Activity的allowTaskReparenting屬性為true,那么當(dāng)應(yīng)用B被啟動(dòng)后,此Activity會(huì)直接從A應(yīng)用任務(wù)棧轉(zhuǎn)移至B應(yīng)用的任務(wù)棧中。
4.singleInstance
單實(shí)例模式。這是一種加強(qiáng)的singleTask模式。它除了具有sigleTask所有特性外,還增加了一點(diǎn),就是具有此種模式的Activity只能單獨(dú)位于一個(gè)任務(wù)棧中。打個(gè)比方來(lái)說(shuō),若Activity A為singleInstance模式,當(dāng)A啟動(dòng),系統(tǒng)會(huì)為他創(chuàng)建一個(gè)新的任務(wù)棧并將A入棧,由于棧內(nèi)復(fù)用特性,后續(xù)請(qǐng)求均不會(huì)創(chuàng)建A,除非這個(gè)獨(dú)特的任務(wù)棧被系統(tǒng)銷毀了。
指定啟動(dòng)模式的方法
1.第一種是在Android的Menifest通過(guò)launchMode屬性來(lái)指定,如下:
<activity android:name=".SecondActivity"
android:launchMode="singleTask"
android:taskAffinity="MyActivity"/>
2.另一種是在Activity內(nèi)通過(guò)在Intent設(shè)置標(biāo)志位來(lái)指定,如下:
Intent intent = new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
3.這兩種方式都可以指定Activity的啟動(dòng)模式,但二者有區(qū)別。其一,優(yōu)先級(jí)上來(lái)講,第二種方法要高于第一種;其二,限定范圍上,第一種方法無(wú)法直接設(shè)定FLAG_ACTIVITY_CLEAR_TOP標(biāo)識(shí),而第二種方法無(wú)法指定singleInstance模式。
四.Activity的Flags
Activity的Flags有很多,我們主要分析一些較常用的標(biāo)記位。
標(biāo)記位的做有很多,有的標(biāo)記為可以設(shè)定Activity的啟動(dòng)模式,比如FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_SINGLE_TOP等;還有的標(biāo)記位可以影響Activity的運(yùn)行狀態(tài),比如FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS等。
大部分情況下,我們不需要為Activity設(shè)置標(biāo)記位,在使用標(biāo)記位時(shí),要注意有的標(biāo)記位是系統(tǒng)內(nèi)部使用的,應(yīng)用程序不需要手動(dòng)設(shè)置這些標(biāo)記位以防出現(xiàn)問(wèn)題。
-
FLAG_ACTIVITY_NEW_TASK
此標(biāo)記位作用是為Activity指定singleTask啟動(dòng)模式,其效果合在XML中指定該啟動(dòng)模式相同。 -
FLAG_ACTIVITY_SINGLE_TOP
此標(biāo)記位作用是為Activity指定singleInstance啟動(dòng)模式,其效果合在XML中指定該啟動(dòng)模式相同。 -
FLAG_ACTIVITY_CLEAR_TOP
具有該標(biāo)記位的Activity啟動(dòng)時(shí),若啟動(dòng)的Activity為singleTask啟動(dòng)模式,則同一任務(wù)棧內(nèi)它之上的Activity都會(huì)出棧;若啟動(dòng)的Activity為standard啟動(dòng)模式,則同一任務(wù)棧內(nèi)連同它之上的Activity都會(huì)出棧,系統(tǒng)會(huì)重建一個(gè)新的Activity入棧。 -
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
設(shè)置該標(biāo)記位的Activity不會(huì)出現(xiàn)在歷史Activity列表,當(dāng)某些情況下我們不希望用戶通過(guò)歷史列表回到我們這個(gè)Activity時(shí)較為有用。它等同于在XML中指定屬性android:excludeFromRecents="true"。
幫忙點(diǎn)個(gè)贊再走嘛~
點(diǎn)贊暴富- 【個(gè)人主頁(yè)】 點(diǎn)擊關(guān)注我,TuTu兔 會(huì)持續(xù)更新分享更多姿勢(shì)喲~ (????) ~

