《Android開發藝術探索》——第一章:Activity的生命週期和啟動模式
目錄
Activity生命週期全面分析
典型情況是指使用者參與的情況下,Activity所經過的生命週期的變化;
異常情況是指Activity被系統回收或者由於當前裝置的Configuration發生改變從而導致Activity被銷燬重建。
典型情況下的生命週期分析
onCreate:表示Activity正在被建立,這是生命週期的第一個方法,在這個方法中,我們可以做一些初始化的工作,比如呼叫onContentView去載入介面佈局資源,初始化Activity所需資料等。
onRestart:表示Activity正在重新啟動,一般情況下,噹噹前Activity從不可見重新變為可見時,onRestart就會被呼叫,這總情況一般是使用者行為所導致的,比如使用者按home鍵切換到桌面或者使用者打開了一個新的Activity,這時當前的Activity就會被暫停,也就是onPause和onStop方法被執行了,接著使用者又回到了這個Activity,就會出現這種情況。
onStart:表示Activity正在被啟動,即將開始,這個時候Activity已經可見了,但是還沒有出現在前臺,還無法和使用者互動,這個時候我們可以理解為Activity已經啟動了,但是我們還沒有看見。
onResume:表示Activity已經可見了,並且出現在前臺,並開始活動了,要注意這個和onStart的對比,這兩個都表示Activity已經可見了,但是onStart的時候Activity還處於後臺,onResume的時候Activity才顯示到前臺。
onPause:表示Activity正在停止,正常情況下,緊接著onStop就會被呼叫,在特殊情況下,如果這個時候再快速的回到當前Activity,那麼onResume就會被呼叫。此時可以做一些資料儲存,停止動畫等工作,但是注意不要太耗時了,因為這樣會影響到新的Activity的顯示,onPause必須先執行完,新Activity的onResume才會執行。
onStop:表示Activity即將停止,同樣可以做一些輕量級的資源回收,但是不要太耗時了。
onDestroy:表示Activity即將被銷燬,這是Activity生命週期的最後一個回撥,在這裡我們可以做一些最後的回收工作和資源釋放。

Activity生命週期的切換過程
具體場景說明:
1.針對一個特定的Activity,第一次啟動,回撥如下:onCreate ——> onStart ——> onResume。
2.當用戶開啟新的Activity或者切換到桌面的時候,回撥如下:onPause ——> onStop ——> 這裡有一種特殊的情況就是,如果新的Activity採取了透明的主題的話,那麼當前Activity不會回撥onStop。
3.當用戶再次回到原來的Activity,回撥如下:onRestart ——> onStart ——> onResume。
4.當用戶按back鍵的時候回撥如下:onPause ———> onStop ——> onDestroy。
5.當Activity被系統回收的時候再次開啟,生命週期回撥方法和1是一樣的,但是你要注意一下就是隻是生命週期一樣,不代表所有的程序都是一樣的,這個問題等下回詳細分析。
6.從整個生命週期來說,onCreate和onDestroy是配套的,分別標示著Activity的建立和銷燬,並且只可能有一次呼叫,從Activity是否可見來說,onStart和onStop是配套的,隨著使用者的操作和裝置螢幕的點亮和熄滅,這兩個方法可能被呼叫多次,從Activity是否在前臺來說,onResume和onPause是配套的,隨著使用者操作或者裝置的點亮和熄滅,這兩個方法可能被多次呼叫。
這裡提出兩個問題:
1.onStart和onResume,onPause和onStop從描述上都差不多,對我們來說有什麼實質性的不同呢?
答:onStart和onStop是從Activity是否可見這個角度來回調的,而onResume和onPause是從Activity是否位於前臺這個角度來回調的,除了這種區別,在實際的使用中,沒有其他明顯的區別。
2.假設當前Activity為A,如果使用者打開了一個新的Activity為B,那麼B的onResume和A的onPause誰先執行尼?
答:當新的Activity啟動的時候,舊的Activity的onPause方法會先執行,然後才啟動新的Activity。也就是說,不能在onPause中做重量級的操作,因為必須在onPause執行完成以後新的Activity才能Resume。
異常情況下的生命週期分析
1.情況1:資源相關的系統配置發生改變導致Activity被殺死並重新建立
比如當前Activity處於豎屏,我們突然旋轉螢幕,由於系統配置發生了改變,在預設情況下,Activity會被銷燬並且重新建立,當然我們也可以阻止系統重新建立我們的Activity。
預設情況下,如果我們的Activity不做特殊處理,那麼當系統配置發生改變之後,Activity就會銷燬並且重新建立,可以看圖:

異常情況下Activity的重建過程
當系統配置發生改變的時候,Activity會被銷燬,其onPause,onStop,onDestroy均會被呼叫,同時由於Activity是異常情況下終止的,系統會呼叫 onSaveInstanceState 來儲存當前Activity的狀態, 這個方法呼叫的時機是在onStop之前,他和onPause沒有既定的時序關係,他即可能在onPause之前呼叫,也有可能在之後呼叫。
當我們onSaveInstanceState儲存到Bundler物件作為引數傳遞給 onRestoreInstanceState 和onCreate方法,因此我們可以通過onRestoreInstanceState和onCreate方法來判斷Activity是否被重建。如果被重建了,我們就取出之前的資料恢復, 從時序上來說,onRestoreInstanceState的呼叫時機應該在onStart之後。
這裡可以簡單的這麼理解,系統只在Activity異常終止的情況下才會呼叫onSaveInstanceState和onRestoreInstanceState來儲存和恢復資料,其他情況不會觸發。
2.情況2:資源記憶體不足導致低優先順序的Activity被殺死
Activity按照優先順序的從高往低,可以分為三種:
- 前臺Activity:正在和使用者互動的Activity,優先順序最高。
- 可見但非前臺Activity:比如對話方塊,導致Activity可見但是位於後臺無法和使用者直接互動。
- 後臺Activity:已經被暫停的Activity,比如執行了onStop,優先順序最低。
當系統記憶體不足的時候,系統就會按照上述優先順序去殺死目標Activity所在的程序,並且在後續通過onSaveInstanceState和onRestoreInstanceState來儲存和恢復資料。
Activity的啟動模式
Activity的LaunchMode
standard
standard:標準模式,這也是系統的預設模式,每次啟動一個Activity都會重新建立一個例項,是否這個例項已經存在。在這種模式下,誰啟動了這個Activity,那麼這個Activity就執行在啟動它的Activity所在的棧內。
當我們用ApplicationContext去啟動standard模式的Activity的時候就會報錯,因為我們的standard模式的Activity預設會進入啟動它的Activity所屬的任務棧中,但是由於非Activity型別的Context(如ApplicationContext)並沒有所謂的任務棧,所以這就有問題了,解決這個問題,就是待啟動Activity指定FLAG_ACTIVITY_TASK標記位,這樣啟動的時候就會為他建立一個新的任務棧,這個時候待啟動Activity實際上是以singleTask模式啟動的。
singleTop
singleTop:棧頂複用模式,在這個模式下,如果新的Activity已經位於任務棧的棧頂,那麼此Activity不會被重新建立,同時他的onNewIntent方法會被呼叫,通過此方法的引數我們可以取出當前請求的資訊,需要注意的是,這個Activity的onCreate,onStart不會被系統呼叫,因為他並沒有發生改變。
singTask
singTask:棧內複用模式,這是一種單例項模式,在這種模式下,只要Activity在一個棧記憶體在,那麼多次啟動此Activity都不會建立例項,和singTop一樣,系統也會回撥其onNewIntent方法。
singleInstance
singleInstance:單例項模式,這是一種加強的singleTask的模式,他除了具有singleTask的所有屬性之外,還加強了一點,那就是具有此模式下的Activity只能單獨的處於一個任務棧中,換句話說,比如ActivityA是singleInstance模式,當A啟動的時候,系統會為建立建立一個新的任務棧,然後A獨立在這個任務棧中,由於棧內複用的特性,後續的請求均不會建立新的Activity,除非這個獨特的任務棧被系統銷燬了。
如何給Activity指定啟動模式?
有兩種方法,第一種是通過清單檔案為Activity指定
<activity android:name=".SecondActivity" android:launchMode="singleTask"/>
另一種啟情況就是通過intent的標誌位為Activity指定啟動模式
Intent intent = new Intent(); intent.setClass(this,SecondActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);
Activity 的 Flags
FLAG_ACTIVITY_NEW_TASK
這個標誌位的作用是為Activity指向‘singleTask’啟動模式,其效果和XML中指定該模式相同
FLAG_ACTIVITY_SINGLE_TOP
這個標誌位的作用是為Activity指向‘singleTop’啟動模式,其效果和XML中指定該模式相同
FLAG_ACTIVITY_CLEAR_TOP
具有此標記位的Activity,當他啟動時,在同一個任務棧中所有位於他上面的Activity都要出棧,這個模式一般需要和FLAG_ ACTIVITY_ NEW _ TASK配合使用,在這種情況下,被啟動的Activity的例項如果已經存在,那麼系統就會呼叫它的onNewIntent,如果被啟動的Activity採用標準模式,那麼他連同他之上的Activity都要出棧,系統會建立新的Activity例項並放入棧頂
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有此標記位的Activity,不會出現在歷史Activity的列表當中,當某種情況下我們不希望使用者通過歷史列表回到我們的Activity的時候就使用這個標記位了,他等同於在XML中指定Activity的屬性: android:excludeFromRecents="true"
intentFilter的匹配規則
我們知道,啟動Activity分為兩種,顯示呼叫和隱式呼叫,二者的區別這裡就不多講了,顯示呼叫需要明確的指定被啟動物件的元件資訊,包括包名和類名,而隱式意圖則不需要明確指定呼叫資訊,原則上一個intent不應該即是顯式呼叫又是隱式呼叫,如果二者共存的話以顯式呼叫為主,顯式呼叫很簡單,這裡主要介紹隱式呼叫,隱式呼叫需要intent能夠匹配目標元件的IntentFilter中所設定的過濾資訊,如果不匹配將無法啟動目標Activity,IntentFilter中的過濾資訊有 action,category,data ,下面是一個過濾規則的例項:
<activity android:name=".CodeActivity" android:configChanges="screenLayout" android:launchMode="singleTask" android:taskAffinity="com.liuguilin.activitysample1"> <intent-filter> <action android:name="com.liuguilin.activitysample.c" /> <action android:name="com.liuguilin.activitysample.d" /> <category android:name="com.liuguilin.category.c" /> <category android:name="com.liuguilin.category.d" /> <data android:mimeType="text/plain" /> </intent-filter> </activity>
只有一個intent同時匹配action類別,category類別,data類別才算是匹配完成,只有完全匹配才能成功啟動目標Activity。
1.action的匹配規則
action的匹配需求就是intent中的action存在且必和過濾規則一樣的action,這裡需要注意的是他和category匹配規則的不同,另外,action區分大小寫,大小寫不同的字串匹配也會失敗。
2.category的匹配規則
category的匹配規則和action不同,它要求Intent中如果含有category,那麼所有的category都必須和過濾規則中的其中一個category相同。
Intent中可以沒有category,原因是系統在呼叫startActivity或者startActivityForResult的時候會預設為Intent加上“android.intent.category.DEFAULT”這個category。
3.data匹配規則
data的匹配規則和action類似,它也要求Intent中必須含有data資料,並且data資料能夠完全匹配過濾規則中的某一個data.這裡的完全匹配是指過濾規則中出現的data部分也出現在了Intent中的data中。
參考資料:
《Android開發藝術探索》
ofollow,noindex">Android開發藝術探索筆記