關(guān)于Activity攒巍,是我們接觸Android時(shí)頻繁了解的東西嗽仪。其生命周期,啟動(dòng)模式等內(nèi)容也耳熟能詳柒莉。今天將系統(tǒng)而全面的總結(jié)Activity中的內(nèi)容闻坚。
一、Activity的生命周期
本節(jié)內(nèi)容將生命周期的情況分為兩部分介紹兢孝,第一部分先了解典型的生命周期的7個(gè)部分及Activity的狀態(tài)鲤氢。第二部分會(huì)介紹Activity在一些特殊情況下的生命周期的經(jīng)歷過程。
1.典型的生命周期的了解
先上經(jīng)典圖片西潘。
關(guān)于這張圖片卷玉,我們可能在初學(xué)Android時(shí)就有接觸,今天我們繼續(xù)回顧一下喷市。
在正常情況下相种,一個(gè)Activity從啟動(dòng)到結(jié)束會(huì)以如下順序經(jīng)歷整個(gè)生命周期:
onCreate()->onStart()->onResume()->onPause()->onStop()->onDestory()。包含了六個(gè)部分品姓,還有一個(gè)onRestart()沒有調(diào)用寝并,下面我們一一介紹這七部分內(nèi)容。
(1) onCreate():當(dāng) Activity 第一次創(chuàng)建時(shí)會(huì)被調(diào)用腹备。這是生命周期的第一個(gè)方法衬潦。在這個(gè)方法中,可以做一些初始化工作植酥,比如調(diào)用setContentView去加載界面布局資源镀岛,初始化Activity所需的數(shù)據(jù)。當(dāng)然也可借助onCreate()方法中的Bundle對象來回復(fù)異常情況下Activity結(jié)束時(shí)的狀態(tài)(后面會(huì)介紹)友驮。
(2) onRestart():表示Activity正在重新啟動(dòng)漂羊。一般情況下,當(dāng)當(dāng)前Activity從不可見重新變?yōu)榭梢姞顟B(tài)時(shí)卸留,onRestart就會(huì)被調(diào)用走越。這種情形一般是用戶行為導(dǎo)致的,比如用戶按Home鍵切換到桌面或打開了另一個(gè)新的Activity耻瑟,接著用戶又回到了這個(gè)Actvity旨指。(關(guān)于這部分生命周期的歷經(jīng)過程,后面會(huì)介紹喳整。)
(3) onStart(): 表示Activity正在被啟動(dòng)谆构,即將開始,這時(shí)Activity已經(jīng)出現(xiàn)了算柳,但是還沒有出現(xiàn)在前臺低淡,無法與用戶交互。這個(gè)時(shí)候可以理解為Activity已經(jīng)顯示出來瞬项,但是我們還看不到蔗蹋。
(4) onResume():表示Activity已經(jīng)可見了,并且出現(xiàn)在前臺并開始活動(dòng)囱淋。需要和onStart()對比猪杭,onStart的時(shí)候Activity還在后臺,onResume的時(shí)候Activity才顯示到前臺妥衣。
(5) onPause():表示 Activity正在停止皂吮,仍可見,正常情況下税手,緊接著onStop就會(huì)被調(diào)用蜂筹。在特殊情況下,如果這個(gè)時(shí)候快速地回到當(dāng)前Activity芦倒,那么onResume就會(huì)被調(diào)用(極端情況)艺挪。onPause中不能進(jìn)行耗時(shí)操作,會(huì)影響到新Activity的顯示兵扬。因?yàn)閛nPause必須執(zhí)行完麻裳,新的Activity的onResume才會(huì)執(zhí)行。
(6) onStop():表示Activity即將停止器钟,不可見津坑,位于后臺“涟裕可以做稍微重量級的回收工作疆瑰,同樣不能太耗時(shí)。
(7) onDestory():表示Activity即將銷毀昙啄,這是Activity生命周期的最后一個(gè)回調(diào)乃摹,可以做一些回收工作和最終的資源回收。
在平常的開發(fā)中跟衅,我們經(jīng)常用到的就是 onCreate()和onDestory()孵睬,做一些初始化和回收操作。
生命周期的幾種普通情況
①針對一個(gè)特定的Activity伶跷,第一次啟動(dòng)掰读,回調(diào)如下:onCreate()->onStart()->onResume()
②用戶打開新的Activiy的時(shí)候,上述Activity的回調(diào)如下:onPause()->onStop()
③再次回到原Activity時(shí)叭莫,回調(diào)如下:onRestart()->onStart()->onResume()
④按back鍵回退時(shí)蹈集,回調(diào)如下:onPause()->onStop()->onDestory()
⑤按Home鍵切換到桌面后又回到該Actitivy,回調(diào)如下:onPause()->onStop()->onRestart()->onStart()->onResume()
⑥調(diào)用finish()方法后雇初,回調(diào)如下:onDestory()(以在onCreate()方法中調(diào)用為例拢肆,不同方法中回調(diào)不同,通常都是在onCreate()方法中調(diào)用)
2.特殊情況下的生命周期
上面是普通情況下Activity生命周期的一些流程,但是在一些特殊情況下郭怪,Activity的生命周期的經(jīng)歷有些異常支示,下面就是兩種特殊情況。
①橫豎屏切換
在橫豎屏切換的過程中鄙才,會(huì)發(fā)生Activity被銷毀并重建的過程颂鸿。
在了解這種情況下的生命周期時(shí),首先應(yīng)該了解這兩個(gè)回調(diào):onSaveInstanceState和onRestoreInstanceState攒庵。
在Activity由于異常情況下終止時(shí)嘴纺,系統(tǒng)會(huì)調(diào)用onSaveInstanceState來保存當(dāng)前Activity的狀態(tài)。這個(gè)方法的調(diào)用是在onStop之前浓冒,它和onPause沒有既定的時(shí)序關(guān)系栽渴,該方法只在Activity被異常終止的情況下調(diào)用。當(dāng)異常終止的Activity被重建以后稳懒,系統(tǒng)會(huì)調(diào)用onRestoreInstanceState闲擦,并且把Activity銷毀時(shí)onSaveInstanceState方法所保存的Bundle對象參數(shù)同時(shí)傳遞給onSaveInstanceState和onCreate方法。因此僚祷,可以通過onRestoreInstanceState方法來恢復(fù)Activity的狀態(tài)佛致,該方法的調(diào)用時(shí)機(jī)是在onStart之后。其中onCreate和onRestoreInstanceState方法來恢復(fù)Activity的狀態(tài)的區(qū)別:onRestoreInstanceState回調(diào)則表明其中Bundle對象非空辙谜,不用加非空判斷俺榆。onCreate需要非空判斷。建議使用onRestoreInstanceState装哆。
橫豎屏切換的生命周期:onPause()->onSaveInstanceState()-> onStop()->onDestroy()->onCreate()->onStart()->onRestoreInstanceState->onResume()
可以通過在AndroidManifest文件的Activity中指定如下屬性:
android:configChanges = "orientation| screenSize"
來避免橫豎屏切換時(shí)罐脊,Activity的銷毀和重建,而是回調(diào)了下面的方法:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
②資源內(nèi)存不足導(dǎo)致優(yōu)先級低的Activity被殺死
Activity優(yōu)先級的劃分和下面的Activity的三種運(yùn)行狀態(tài)是對應(yīng)的蜕琴。
(1) 前臺Activity——正在和用戶交互的Activity萍桌,優(yōu)先級最高。
(2) 可見但非前臺Activity——比如Activity中彈出了一個(gè)對話框凌简,導(dǎo)致Activity可見但是位于后臺無法和用戶交互上炎。
(3) 后臺Activity——已經(jīng)被暫停的Activity,比如執(zhí)行了onStop雏搂,優(yōu)先級最低藕施。
當(dāng)系統(tǒng)內(nèi)存不足時(shí),會(huì)按照上述優(yōu)先級從低到高去殺死目標(biāo)Activity所在的進(jìn)程凸郑。我們在平常使用手機(jī)時(shí)裳食,能經(jīng)常感受到這一現(xiàn)象。這種情況下數(shù)組存儲(chǔ)和恢復(fù)過程和上述情況一致芙沥,生命周期情況也一樣诲祸。
3.Activity的三種運(yùn)行狀態(tài)
①Resumed(活動(dòng)狀態(tài))
又叫Running狀態(tài)浊吏,這個(gè)Activity正在屏幕上顯示,并且有用戶焦點(diǎn)救氯。這個(gè)很好理解找田,就是用戶正在操作的那個(gè)界面。
②Paused(暫停狀態(tài))
這是一個(gè)比較不常見的狀態(tài)径密。這個(gè)Activity在屏幕上是可見的午阵,但是并不是在屏幕最前端的那個(gè)Activity躺孝。比如有另一個(gè)非全屏或者透明的Activity是Resumed狀態(tài)享扔,沒有完全遮蓋這個(gè)Activity。
③Stopped(停止?fàn)顟B(tài))
當(dāng)Activity完全不可見時(shí)植袍,此時(shí)Activity還在后臺運(yùn)行惧眠,仍然在內(nèi)存中保留Activity的狀態(tài),并不是完全銷毀于个。這個(gè)也很好理解氛魁,當(dāng)跳轉(zhuǎn)的另外一個(gè)界面,之前的界面還在后臺厅篓,按回退按鈕還會(huì)恢復(fù)原來的狀態(tài)秀存,大部分軟件在打開的時(shí)候,直接按Home鍵羽氮,并不會(huì)關(guān)閉它或链,此時(shí)的Activity就是Stopped狀態(tài)。
二档押、Activity的啟動(dòng)模式
1.啟動(dòng)模式的類別
Android提供了四種Activity啟動(dòng)方式:
標(biāo)準(zhǔn)模式(standard)
棧頂復(fù)用模式(singleTop)
棧內(nèi)復(fù)用模式(singleTask)
單例模式(singleInstance)
2.啟動(dòng)模式的結(jié)構(gòu)——棧
Activity的管理是采用任務(wù)棧的形式澳盐,任務(wù)棧采用“后進(jìn)先出”的棧結(jié)構(gòu)。
3.Activity的LaunchMode
(1)標(biāo)準(zhǔn)模式(standard)
每啟動(dòng)一次Activity令宿,就會(huì)創(chuàng)建一個(gè)新的Activity實(shí)例并置于棧頂叼耙。誰啟動(dòng)了這個(gè)Activity,那么這個(gè)Activity就運(yùn)行在啟動(dòng)它的那個(gè)Activity所在的棧中粒没。
例如:Activity A啟動(dòng)了Activity B筛婉,則就會(huì)在A所在的棧頂壓入一個(gè)新的Activity。
特殊情況癞松,如果在Service或Application中啟動(dòng)一個(gè)Activity爽撒,其并沒有所謂的任務(wù)棧,可以使用標(biāo)記位Flag來解決拦惋。解決辦法:為待啟動(dòng)的Activity指定FLAG_ACTIVITY_NEW_TASK標(biāo)記位匆浙,創(chuàng)建一個(gè)新棧。
應(yīng)用場景:絕大多數(shù)Activity厕妖。如果以這種方式啟動(dòng)的Activity被跨進(jìn)程調(diào)用首尼,在5.0之前新啟動(dòng)的Activity實(shí)例會(huì)放入發(fā)送Intent的Task的棧的頂部,盡管它們屬于不同的程序,這似乎有點(diǎn)費(fèi)解看起來也不是那么合理软能,所以在5.0之后迎捺,上述情景會(huì)創(chuàng)建一個(gè)新的Task,新啟動(dòng)的Activity就會(huì)放入剛創(chuàng)建的Task中查排,這樣就合理的多了凳枝。
(2)棧頂復(fù)用模式(singleTop)
如果需要新建的Activity位于任務(wù)棧棧頂,那么此Activity的實(shí)例就不會(huì)重建跋核,而是重用棧頂?shù)膶?shí)例岖瑰。并回調(diào)如下方法:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
由于不會(huì)重建一個(gè)Activity實(shí)例,則不會(huì)回調(diào)其他生命周期方法砂代。
如果棧頂不是新建的Activity,就會(huì)創(chuàng)建該Activity新的實(shí)例蹋订,并放入棧頂。
應(yīng)用場景:在通知欄點(diǎn)擊收到的通知刻伊,然后需要啟動(dòng)一個(gè)Activity露戒,這個(gè)Activity就可以用singleTop,否則每次點(diǎn)擊都會(huì)新建一個(gè)Activity捶箱。當(dāng)然實(shí)際的開發(fā)過程中智什,測試妹紙沒準(zhǔn)給你提過這樣的bug:某個(gè)場景下連續(xù)快速點(diǎn)擊,啟動(dòng)了兩個(gè)Activity丁屎。如果這個(gè)時(shí)候待啟動(dòng)的Activity使用 singleTop模式也是可以避免這個(gè)Bug的荠锭。同standard模式,如果是外部程序啟動(dòng)singleTop的Activity悦屏,在Android 5.0之前新創(chuàng)建的Activity會(huì)位于調(diào)用者的Task中节沦,5.0及以后會(huì)放入新的Task中。
(3)棧內(nèi)復(fù)用模式(singleTask)
該模式是一種單例模式础爬,即一個(gè)棧內(nèi)只有一個(gè)該Activity實(shí)例甫贯。該模式,可以通過在AndroidManifest文件的Activity中指定該Activity需要加載到那個(gè)棧中看蚜,即singleTask的Activity可以指定想要加載的目標(biāo)棧叫搁。singleTask和taskAffinity配合使用,指定開啟的Activity加入到哪個(gè)棧中供炎。
<activity android:name=".Activity1"
android:launchMode="singleTask"
android:taskAffinity="com.lvr.task"
android:label="@string/app_name">
</activity>
關(guān)于taskAffinity的值:每個(gè)Activity都有taskAffinity屬性渴逻,這個(gè)屬性指出了它希望進(jìn)入的Task。如果一個(gè)Activity沒有顯式的指明該Activity的taskAffinity音诫,那么它的這個(gè)屬性就等于Application指明的taskAffinity惨奕,如果Application也沒有指明,那么該taskAffinity的值就等于包名竭钝。
執(zhí)行邏輯:
在這種模式下梨撞,如果Activity指定的棧不存在雹洗,則創(chuàng)建一個(gè)棧,并把創(chuàng)建的Activity壓入棧內(nèi)卧波。如果Activity指定的棧存在时肿,如果其中沒有該Activity實(shí)例,則會(huì)創(chuàng)建Activity并壓入棧頂港粱,如果其中有該Activity實(shí)例螃成,則把該Activity實(shí)例之上的Activity殺死清除出棧,重用并讓該Activity實(shí)例處在棧頂查坪,然后調(diào)用onNewIntent()方法寸宏。
對應(yīng)如下三種情況:
應(yīng)用場景:大多數(shù)App的主頁。對于大部分應(yīng)用咪惠,當(dāng)我們在主界面點(diǎn)擊回退按鈕的時(shí)候都是退出應(yīng)用击吱,那么當(dāng)我們第一次進(jìn)入主界面之后淋淀,主界面位于棧底遥昧,以后不管我們打開了多少個(gè)Activity,只要我們再次回到主界面朵纷,都應(yīng)該使用將主界面Activity上所有的Activity移除的方式來讓主界面Activity處于棧頂炭臭,而不是往棧頂新加一個(gè)主界面Activity的實(shí)例,通過這種方式能夠保證退出應(yīng)用時(shí)所有的Activity都能報(bào)銷毀袍辞。在跨應(yīng)用Intent傳遞時(shí)鞋仍,如果系統(tǒng)中不存在singleTask Activity的實(shí)例,那么將創(chuàng)建一個(gè)新的Task搅吁,然后創(chuàng)建SingleTask Activity的實(shí)例威创,將其放入新的Task中。
(4)單例模式(singleInstance)
作為棧內(nèi)復(fù)用模式(singleTask)的加強(qiáng)版,打開該Activity時(shí)谎懦,直接創(chuàng)建一個(gè)新的任務(wù)棧肚豺,并創(chuàng)建該Activity實(shí)例放入新棧中。一旦該模式的Activity實(shí)例已經(jīng)存在于某個(gè)棧中界拦,任何應(yīng)用再激活該Activity時(shí)都會(huì)重用該棧中的實(shí)例吸申。
應(yīng)用場景:呼叫來電界面。這種模式的使用情況比較罕見享甸,在Launcher中可能使用截碴。或者你確定你需要使Activity只有一個(gè)實(shí)例蛉威。建議謹(jǐn)慎使用日丹。
3.特殊情況——前臺棧和后臺棧的交互
假如目前有兩個(gè)任務(wù)棧。前臺任務(wù)棧為AB蚯嫌,后臺任務(wù)棧為CD哲虾,這里假設(shè)CD的啟動(dòng)模式均為singleTask,現(xiàn)在請求啟動(dòng)D割坠,那么這個(gè)后臺的任務(wù)棧都會(huì)被切換到前臺,這個(gè)時(shí)候整個(gè)后退列表就變成了ABCD妒牙。當(dāng)用戶按back返回時(shí)彼哼,列表中的activity會(huì)一一出棧,如下圖湘今。
如果不是請求啟動(dòng)D而是啟動(dòng)C敢朱,那么情況又不一樣,如下圖摩瞎。
調(diào)用SingleTask模式的后臺任務(wù)棧中的Activity拴签,會(huì)把整個(gè)棧的Actvity壓入當(dāng)前棧的棧頂。singleTask會(huì)具有clearTop特性旗们,把之上的棧內(nèi)Activity清除蚓哩。
4.Activity的Flags
Activity的Flags很多,這里介紹集中常用的上渴,用于設(shè)定Activity的啟動(dòng)模式岸梨。可以在啟動(dòng)Activity時(shí)稠氮,通過Intent的addFlags()方法設(shè)置曹阔。
**(1)FLAG_ACTIVITY_NEW_TASK **
其效果與指定Activity為singleTask模式一致。
(2)FLAG_ACTIVITY_SINGLE_TOP
其效果與指定Activity為singleTop模式一致隔披。
(3)FLAG_ACTIVITY_CLEAR_TOP
具有此標(biāo)記位的Activity赃份,當(dāng)它啟動(dòng)時(shí),在同一個(gè)任務(wù)棧中所有位于它上面的Activity都要出棧奢米。如果和singleTask模式一起出現(xiàn)抓韩,若被啟動(dòng)的Activity已經(jīng)存在棧中,則清除其之上的Activity鬓长,并調(diào)用該Activity的onNewIntent方法谒拴。如果被啟動(dòng)的Activity采用standard模式,那么該Activity連同之上的所有Activity出棧痢士,然后創(chuàng)建新的Activity實(shí)例并壓入棧中彪薛。
以上就是本篇文章的內(nèi)容。本篇文章的棧操作的圖片來自于xybCoder怠蹂,特別感謝善延!