關于Activity,是我們接觸Android時頻繁了解的東西。其生命周期,啟動模式等內容也耳熟能詳。今天將系統而全面的總結Activity中的內容。
一、Activity的生命周期
本節內容將生命周期的情況分為兩部分介紹,第一部分先了解典型的生命周期的7個部分及Activity的狀態。第二部分會介紹Activity在一些特殊情況下的生命周期的經歷過程。
1.典型的生命周期的了解
先上經典圖片。
關于這張圖片,我們可能在初學Android時就有接觸,今天我們繼續回顧一下。
在正常情況下,一個Activity從啟動到結束會以如下順序經歷整個生命周期:
onCreate()->onStart()->onResume()->onPause()->onStop()->onDestory()。包含了六個部分,還有一個onRestart()沒有調用,下面我們一一介紹這七部分內容。
(1) onCreate():當 Activity 第一次創建時會被調用。這是生命周期的第一個方法。在這個方法中,可以做一些初始化工作,比如調用setContentView去加載界面布局資源,初始化Activity所需的數據。當然也可借助onCreate()方法中的Bundle對象來回復異常情況下Activity結束時的狀態(后面會介紹)。
(2) onRestart():表示Activity正在重新啟動。一般情況下,當當前Activity從不可見重新變為可見狀態時,onRestart就會被調用。這種情形一般是用戶行為導致的,比如用戶按Home鍵切換到桌面或打開了另一個新的Activity,接著用戶又回到了這個Actvity。(關于這部分生命周期的歷經過程,后面會介紹。)
(3) onStart(): 表示Activity正在被啟動,即將開始,這時Activity已經出現了,但是還沒有出現在前臺,無法與用戶交互。這個時候可以理解為Activity已經顯示出來,但是我們還看不到。
(4) onResume():表示Activity已經可見了,并且出現在前臺并開始活動。需要和onStart()對比,onStart的時候Activity還在后臺,onResume的時候Activity才顯示到前臺。
(5) onPause():表示 Activity正在停止,仍可見,正常情況下,緊接著onStop就會被調用。在特殊情況下,如果這個時候快速地回到當前Activity,那么onResume就會被調用(極端情況)。onPause中不能進行耗時操作,會影響到新Activity的顯示。因為onPause必須執行完,新的Activity的onResume才會執行。
(6) onStop():表示Activity即將停止,不可見,位于后臺??梢宰錾晕⒅亓考壍幕厥展ぷ?,同樣不能太耗時。
(7) onDestory():表示Activity即將銷毀,這是Activity生命周期的最后一個回調,可以做一些回收工作和最終的資源回收。
在平常的開發中,我們經常用到的就是 onCreate()和onDestory(),做一些初始化和回收操作。
生命周期的幾種普通情況
①針對一個特定的Activity,第一次啟動,回調如下:onCreate()->onStart()->onResume()
②用戶打開新的Activiy的時候,上述Activity的回調如下:onPause()->onStop()
③再次回到原Activity時,回調如下:onRestart()->onStart()->onResume()
④按back鍵回退時,回調如下:onPause()->onStop()->onDestory()
⑤按Home鍵切換到桌面后又回到該Actitivy,回調如下:onPause()->onStop()->onRestart()->onStart()->onResume()
⑥調用finish()方法后,回調如下:onDestory()(以在onCreate()方法中調用為例,不同方法中回調不同,通常都是在onCreate()方法中調用)
2.特殊情況下的生命周期
上面是普通情況下Activity生命周期的一些流程,但是在一些特殊情況下,Activity的生命周期的經歷有些異常,下面就是兩種特殊情況。
①橫豎屏切換
在橫豎屏切換的過程中,會發生Activity被銷毀并重建的過程。
在了解這種情況下的生命周期時,首先應該了解這兩個回調:onSaveInstanceState和onRestoreInstanceState。
在Activity由于異常情況下終止時,系統會調用onSaveInstanceState來保存當前Activity的狀態。這個方法的調用是在onStop之前,它和onPause沒有既定的時序關系,該方法只在Activity被異常終止的情況下調用。當異常終止的Activity被重建以后,系統會調用onRestoreInstanceState,并且把Activity銷毀時onSaveInstanceState方法所保存的Bundle對象參數同時傳遞給onSaveInstanceState和onCreate方法。因此,可以通過onRestoreInstanceState方法來恢復Activity的狀態,該方法的調用時機是在onStart之后。其中onCreate和onRestoreInstanceState方法來恢復Activity的狀態的區別:onRestoreInstanceState回調則表明其中Bundle對象非空,不用加非空判斷。onCreate需要非空判斷。建議使用onRestoreInstanceState。
橫豎屏切換的生命周期:onPause()->onSaveInstanceState()-> onStop()->onDestroy()->onCreate()->onStart()->onRestoreInstanceState->onResume()
可以通過在AndroidManifest文件的Activity中指定如下屬性:
android:configChanges = "orientation| screenSize"
來避免橫豎屏切換時,Activity的銷毀和重建,而是回調了下面的方法:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
②資源內存不足導致優先級低的Activity被殺死
Activity優先級的劃分和下面的Activity的三種運行狀態是對應的。
(1) 前臺Activity——正在和用戶交互的Activity,優先級最高。
(2) 可見但非前臺Activity——比如Activity中彈出了一個對話框,導致Activity可見但是位于后臺無法和用戶交互。
(3) 后臺Activity——已經被暫停的Activity,比如執行了onStop,優先級最低。
當系統內存不足時,會按照上述優先級從低到高去殺死目標Activity所在的進程。我們在平常使用手機時,能經常感受到這一現象。這種情況下數組存儲和恢復過程和上述情況一致,生命周期情況也一樣。
3.Activity的三種運行狀態
①Resumed(活動狀態)
又叫Running狀態,這個Activity正在屏幕上顯示,并且有用戶焦點。這個很好理解,就是用戶正在操作的那個界面。
②Paused(暫停狀態)
這是一個比較不常見的狀態。這個Activity在屏幕上是可見的,但是并不是在屏幕最前端的那個Activity。比如有另一個非全屏或者透明的Activity是Resumed狀態,沒有完全遮蓋這個Activity。
③Stopped(停止狀態)
當Activity完全不可見時,此時Activity還在后臺運行,仍然在內存中保留Activity的狀態,并不是完全銷毀。這個也很好理解,當跳轉的另外一個界面,之前的界面還在后臺,按回退按鈕還會恢復原來的狀態,大部分軟件在打開的時候,直接按Home鍵,并不會關閉它,此時的Activity就是Stopped狀態。
二、Activity的啟動模式
1.啟動模式的類別
Android提供了四種Activity啟動方式:
標準模式(standard)
棧頂復用模式(singleTop)
棧內復用模式(singleTask)
單例模式(singleInstance)
2.啟動模式的結構——棧
Activity的管理是采用任務棧的形式,任務棧采用“后進先出”的棧結構。
3.Activity的LaunchMode
(1)標準模式(standard)
每啟動一次Activity,就會創建一個新的Activity實例并置于棧頂。誰啟動了這個Activity,那么這個Activity就運行在啟動它的那個Activity所在的棧中。
例如:Activity A啟動了Activity B,則就會在A所在的棧頂壓入一個新的Activity。
特殊情況,如果在Service或Application中啟動一個Activity,其并沒有所謂的任務棧,可以使用標記位Flag來解決。解決辦法:為待啟動的Activity指定FLAG_ACTIVITY_NEW_TASK標記位,創建一個新棧。
應用場景:絕大多數Activity。如果以這種方式啟動的Activity被跨進程調用,在5.0之前新啟動的Activity實例會放入發送Intent的Task的棧的頂部,盡管它們屬于不同的程序,這似乎有點費解看起來也不是那么合理,所以在5.0之后,上述情景會創建一個新的Task,新啟動的Activity就會放入剛創建的Task中,這樣就合理的多了。
(2)棧頂復用模式(singleTop)
如果需要新建的Activity位于任務棧棧頂,那么此Activity的實例就不會重建,而是重用棧頂的實例。并回調如下方法:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
由于不會重建一個Activity實例,則不會回調其他生命周期方法。
如果棧頂不是新建的Activity,就會創建該Activity新的實例,并放入棧頂。
應用場景:在通知欄點擊收到的通知,然后需要啟動一個Activity,這個Activity就可以用singleTop,否則每次點擊都會新建一個Activity。當然實際的開發過程中,測試妹紙沒準給你提過這樣的bug:某個場景下連續快速點擊,啟動了兩個Activity。如果這個時候待啟動的Activity使用 singleTop模式也是可以避免這個Bug的。同standard模式,如果是外部程序啟動singleTop的Activity,在Android 5.0之前新創建的Activity會位于調用者的Task中,5.0及以后會放入新的Task中。
(3)棧內復用模式(singleTask)
該模式是一種單例模式,即一個棧內只有一個該Activity實例。該模式,可以通過在AndroidManifest文件的Activity中指定該Activity需要加載到那個棧中,即singleTask的Activity可以指定想要加載的目標棧。singleTask和taskAffinity配合使用,指定開啟的Activity加入到哪個棧中。
<activity android:name=".Activity1"
android:launchMode="singleTask"
android:taskAffinity="com.lvr.task"
android:label="@string/app_name">
</activity>
關于taskAffinity的值:每個Activity都有taskAffinity屬性,這個屬性指出了它希望進入的Task。如果一個Activity沒有顯式的指明該Activity的taskAffinity,那么它的這個屬性就等于Application指明的taskAffinity,如果Application也沒有指明,那么該taskAffinity的值就等于包名。
執行邏輯:
在這種模式下,如果Activity指定的棧不存在,則創建一個棧,并把創建的Activity壓入棧內。如果Activity指定的棧存在,如果其中沒有該Activity實例,則會創建Activity并壓入棧頂,如果其中有該Activity實例,則把該Activity實例之上的Activity殺死清除出棧,重用并讓該Activity實例處在棧頂,然后調用onNewIntent()方法。
對應如下三種情況:
應用場景:大多數App的主頁。對于大部分應用,當我們在主界面點擊回退按鈕的時候都是退出應用,那么當我們第一次進入主界面之后,主界面位于棧底,以后不管我們打開了多少個Activity,只要我們再次回到主界面,都應該使用將主界面Activity上所有的Activity移除的方式來讓主界面Activity處于棧頂,而不是往棧頂新加一個主界面Activity的實例,通過這種方式能夠保證退出應用時所有的Activity都能報銷毀。在跨應用Intent傳遞時,如果系統中不存在singleTask Activity的實例,那么將創建一個新的Task,然后創建SingleTask Activity的實例,將其放入新的Task中。
(4)單例模式(singleInstance)
作為棧內復用模式(singleTask)的加強版,打開該Activity時,直接創建一個新的任務棧,并創建該Activity實例放入新棧中。一旦該模式的Activity實例已經存在于某個棧中,任何應用再激活該Activity時都會重用該棧中的實例。
應用場景:呼叫來電界面。這種模式的使用情況比較罕見,在Launcher中可能使用?;蛘吣愦_定你需要使Activity只有一個實例。建議謹慎使用。
3.特殊情況——前臺棧和后臺棧的交互
假如目前有兩個任務棧。前臺任務棧為AB,后臺任務棧為CD,這里假設CD的啟動模式均為singleTask,現在請求啟動D,那么這個后臺的任務棧都會被切換到前臺,這個時候整個后退列表就變成了ABCD。當用戶按back返回時,列表中的activity會一一出棧,如下圖。
如果不是請求啟動D而是啟動C,那么情況又不一樣,如下圖。
調用SingleTask模式的后臺任務棧中的Activity,會把整個棧的Actvity壓入當前棧的棧頂。singleTask會具有clearTop特性,把之上的棧內Activity清除。
4.Activity的Flags
Activity的Flags很多,這里介紹集中常用的,用于設定Activity的啟動模式??梢栽趩覣ctivity時,通過Intent的addFlags()方法設置。
**(1)FLAG_ACTIVITY_NEW_TASK **
其效果與指定Activity為singleTask模式一致。
(2)FLAG_ACTIVITY_SINGLE_TOP
其效果與指定Activity為singleTop模式一致。
(3)FLAG_ACTIVITY_CLEAR_TOP
具有此標記位的Activity,當它啟動時,在同一個任務棧中所有位于它上面的Activity都要出棧。如果和singleTask模式一起出現,若被啟動的Activity已經存在棧中,則清除其之上的Activity,并調用該Activity的onNewIntent方法。如果被啟動的Activity采用standard模式,那么該Activity連同之上的所有Activity出棧,然后創建新的Activity實例并壓入棧中。
以上就是本篇文章的內容。本篇文章的棧操作的圖片來自于xybCoder,特別感謝!