Activity作為Android四大組件中最常用的組件,對其進(jìn)行深入的學(xué)習(xí)是一個初級Android開發(fā)人員成長路上的必修課梁沧。
本篇文章主要針對Activity的生命周期、異常狀態(tài)恢復(fù)坛梁、啟動模式以及Intent隱式啟動做相應(yīng)的深入學(xué)習(xí)奏黑,挖掘Activity的各項(xiàng)進(jìn)階知識。
1.Activity的生命周期
先上一張官方的Activity生命周期圖
接下來我們對Activity生命周期中的各狀態(tài)進(jìn)行逐一分析:
(1)onCreate:該方法只在Activity第一次被創(chuàng)建的時候調(diào)用孩擂。我們常常在其中進(jìn)行一些初始化的操作狼渊,如setContentView、綁定事件、初始化各類數(shù)據(jù)等狈邑。
(2)onStart:該方法表示Activity正在啟動城须。一般發(fā)生在Activity由不可見轉(zhuǎn)變?yōu)榭梢姇r被調(diào)用。(此時的Activity已經(jīng)可見了米苹,但還沒出現(xiàn)在前臺糕伐,無法進(jìn)行交互)
(3)onResume:該方法表示Activity不僅已經(jīng)可見,而且此刻位于前臺蘸嘶,可以與用戶進(jìn)行交互良瞧。此時該Activity一定位于當(dāng)前返回棧的棧頂,且處于運(yùn)行狀態(tài)训唱。
(4)onPause:該方法表示Activity正在停止褥蚯,一般情況下onStop方法會緊接著被調(diào)用。通常我們會在這個方法中去做一些儲存數(shù)據(jù)况增、釋放資源的操作赞庶。此時該Activity將不再位于前臺。注意的是澳骤,該方法中切不可執(zhí)行耗時操作尘执,否則會影響到新Activity的顯示。
(5)onStop:該方法在活動完全不可見時被調(diào)用宴凉,可以在該方法內(nèi)執(zhí)行一些稍微重量級的回收工作誊锭,同樣不可太耗時。
(6)onDestroy:該方法表示Activity即將被銷毀弥锄,這是Activity生命周期中的最后一步丧靡,應(yīng)該在該方法內(nèi)執(zhí)行最終的回收工作和資源釋放。
(7)onRestart:該方法在Activity由停止?fàn)顟B(tài)轉(zhuǎn)為運(yùn)行狀態(tài)的過程中被調(diào)用籽暇,一般發(fā)生在返回到上一個Activity這種情況下温治。
上述7個生命周期中的回調(diào)方法中,除了OnRestart方法戒悠,其他方法都是兩兩相對的熬荆,我們可以從下面幾種角度對它們進(jìn)行加深理解:
從Activity創(chuàng)建和銷毀的角度來看,分別對應(yīng)著OnCreate和OnDestroy绸狐;
從Activity是否可見的角度來看卤恳,分別對應(yīng)著OnStart和OnStop;
從Activity是否位于前臺的角度來看寒矿,分別對應(yīng)著OnResume和OnPause突琳。
下面列舉幾種情況下Activity的執(zhí)行流程:
①Activity啟動:onCreate->onStart->onResume
②打開新Activity或切換到桌面:onPause->onStop(特殊情況,當(dāng)新Activity采用透明主題時符相,當(dāng)前Activity不會回調(diào)onStop)
③回到原Activity:onRestart->onStart->onResume
④按back鍵回退:onPause->onStop->onDestroy
特別說明:
當(dāng)啟動一個新Activity時拆融,一定是先執(zhí)行當(dāng)前Activity的onPause方法后,才會啟動新的Activity,最后執(zhí)行當(dāng)前Activity的onStop方法镜豹。(所以onPause方法中一定不能執(zhí)行耗時操作)
2.Activity異常狀態(tài)下的生命周期
當(dāng)資源相關(guān)的系統(tǒng)配置發(fā)生改變或是系統(tǒng)內(nèi)存不足時傲须,Activity可能會被殺死。由于Activity是被異常銷毀掉的趟脂,所以用戶的一些臨時數(shù)據(jù)需要進(jìn)行保存泰讽,以使該Activity重新創(chuàng)建時能復(fù)現(xiàn)銷毀時的內(nèi)容,如EditText中的內(nèi)容等散怖。
由系統(tǒng)內(nèi)存不足所涉及到的進(jìn)程優(yōu)先級的問題菇绵,參考Android的進(jìn)程優(yōu)先級。
當(dāng)系統(tǒng)配置發(fā)生改變后镇眷,Activity會被銷毀咬最,其onPause、onStop欠动、onDestroy均會被調(diào)用永乌,同時由于Activity是在異常情況下被終止的,所以系統(tǒng)會調(diào)用onSaveInstanceState方法來保存當(dāng)前Activity的狀態(tài)具伍。該方法的調(diào)用時機(jī)在onStop之前翅雏,但和onPause沒有絕對的時序關(guān)系。
當(dāng)Activity被重新創(chuàng)建之后人芽,系統(tǒng)會回調(diào)onRestoreInstanceState方法望几,并把Activity銷毀時在onSaveInstanceState方法中所保存的Bundle作為參數(shù)傳遞到onCreate和onRestoreInstanceState方法中。從時序上來說萤厅,onRestoreInstanceState調(diào)用時機(jī)在onStart之后橄抹。
onRestoreInstanceState和onCreate雖然都能獲得異常時傳入Bundle參數(shù),但是二者還是有一定的區(qū)別:onRestoreInstanceState方法一旦被調(diào)用惕味,其Bundle參數(shù)一定是有值的楼誓;而onCreate方法在正常啟動的時候,其Bundle參數(shù)為null名挥,所以必須進(jìn)行額外的判斷才行疟羹。官方推薦使用onRestoreInstanceState方法進(jìn)行數(shù)據(jù)恢復(fù)。
多次試驗(yàn)后的總結(jié)下禀倔,onSaveInstanceState(Bundle outState)會在以下情況被調(diào)用:
1榄融、當(dāng)用戶按下HOME鍵時。
2蹋艺、從最近應(yīng)用中選擇運(yùn)行其他的程序時剃袍。
3、按下電源按鍵(關(guān)閉屏幕顯示)時捎谨。
4、從當(dāng)前activity啟動一個新的activity時。
5涛救、屏幕方向切換時(無論豎屏切橫屏還是橫屏切豎屏都會調(diào)用)畏邢。
在前4種情況下,當(dāng)前activity的生命周期為:
onPause -> onSaveInstanceState -> onStop -> onRestart -> onStart -> onResume
當(dāng)該activity重新位于前臺時检吆,并不會執(zhí)行onRestoreInstanceState方法舒萎。
第五種情況下,當(dāng)前activity的生命周期為:
onPause -> onSaveInstanceState -> onStop -> onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume
當(dāng)然蹭沛,當(dāng)系統(tǒng)配置發(fā)生變化時臂寝,Activity也能不被重建。通過給Activity指定configChanges屬性可以實(shí)現(xiàn)這一目標(biāo)摊灭,如不想讓Activity在屏幕旋轉(zhuǎn)時重建咆贬,就可以給configChanges屬性添加orientation這個值。
android:configChanges="orientation"
通常我們用的只有l(wèi)ocal(系統(tǒng)語言)帚呼、orientation(屏幕方向)和keyboardHidden(調(diào)出鍵盤)這三個選項(xiàng)掏缎。
3.Activity的啟動模式
系統(tǒng)會將啟動的Activity放入ActivityTask中,該任務(wù)棧遵循后進(jìn)先出的規(guī)則煤杀。當(dāng)然眷蜈,Android中還能通過指定lauchmode的方式來個性化activity在棧中的啟動模式。
Activity有四種啟動模式standard沈自、singleTop酌儒、singleTask和singleInstance。
①standard:activity的默認(rèn)啟動模式枯途。每次啟動一個Activity的時候都會重新創(chuàng)建一個新的實(shí)例壓入棧頂忌怎,不管當(dāng)前棧中是否已存在該Activity。
②singleTop:棧頂復(fù)用模式柔袁。如果當(dāng)前任務(wù)棧的棧頂是該Activity呆躲,那么此Activity不會被重新創(chuàng)建,同時會調(diào)用棧頂Activity的onNewIntent方法捶索,通過此方法獲取當(dāng)前的請求信息插掂。此時該Activity的onCreate、onStart不會被系統(tǒng)調(diào)用腥例,僅執(zhí)行onPause -> onNewIntent -> onResume辅甥;如果新Activity的實(shí)例在任務(wù)棧中已存在但并未位于棧頂,那么新Activity則依舊會重新創(chuàng)建燎竖。
③singleTask:棧內(nèi)復(fù)用模式璃弄。這是一種單實(shí)例模式,該模式下构回,只要當(dāng)前任務(wù)棧內(nèi)存在即將要啟動的Activity(不管在棧內(nèi)何處)夏块,那么當(dāng)前棧中該Activity上面的所有Activity都將出棧疏咐,并且該Activity將位于棧頂。和singleTop一樣脐供,singleTask也會調(diào)用該Activity的onNewIntent方法浑塞。(注意:singleTask模式下可以指定該Activity啟動所需要的任務(wù)棧,若指定任務(wù)棧不存在政己,則會新建對應(yīng)的任務(wù)棧后再把該Activity新建的實(shí)例放進(jìn)去)酌壕。
④singleInstance:單實(shí)例模式。指定為singleInstance的Activity會啟用一個新的任務(wù)棧來管理自身歇由。只要該Activity未銷毀卵牍,由于棧內(nèi)復(fù)用的特性,后續(xù)的請求不會再創(chuàng)建新的任務(wù)棧沦泌,會一直復(fù)用處于該任務(wù)棧內(nèi)的Activity糊昙。
特殊情況:TaskAffinity
上面提到在singleTask模式下,Activity需要選擇自己所指定的任務(wù)棧赦肃,那么這個指定的任務(wù)棧又是在哪實(shí)現(xiàn)的呢溅蛉?
答案就在TaskAffinity這個屬性上。該參數(shù)能標(biāo)識Activity所需任務(wù)棧的名字他宛,默認(rèn)情況下所有Acitivity的任務(wù)棧都為應(yīng)用的包名船侧。TaskAffinity屬性的值為字符串,且中間必須包含包名分隔符“.”厅各。TaskAffinity屬性主要和singleTask模式或者allowTaskReparenting屬性配對使用镜撩,在其他情況下沒有意義。
當(dāng)TaskAffinity和singleTask模式配對使用時队塘,待啟動的Activity會運(yùn)行在TaskAffinity指定的任務(wù)棧中袁梗。
當(dāng)TaskAffinity和allowTaskReparenting配對使用時,情況較為復(fù)雜憔古。例如有兩個應(yīng)用A和B遮怜,A啟動了B中的Activity并且該Activity設(shè)置的allowTaskReparenting屬性為true,那么當(dāng)用戶按home建回到桌面后再點(diǎn)擊應(yīng)用B圖標(biāo)鸿市,則不是啟動了B的Launch Activity锯梁,而是重新顯示的之前被A所啟動的那個Activity。
除了通過launchmode來指定Activity的啟動模式焰情,還能通過Intent來動態(tài)指定Activity的啟動模式陌凳。其中,Intent動態(tài)指定的優(yōu)先級高于在xml中的靜態(tài)注冊方式内舟。
動態(tài)指定主要是通過往Intent中添加Flag實(shí)現(xiàn)合敦,如
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
以下列舉幾個常見的標(biāo)記位,稍作理解即可验游。
FLAG_ACTIVITY_NEW_TASK:和在xml中指定singleTask模式相同
FLAG_ACTIVITY_SINGLE_TOP:和在xml中指定singleTop模式相同
FLAG_ACTIVITY_CLEAR_TOP:啟動該Activity時充岛,與其同一任務(wù)棧中所有位于它上面的Activity都要出棧保檐。如果被啟動的Activity采用standard模式,那么連同它之上的Activity都要出棧裸准,系統(tǒng)再創(chuàng)建新的Activity實(shí)例放入棧頂展东。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有此標(biāo)記的Activity不會出現(xiàn)在歷史Activity列表中赔硫。等同于在xml中指定Activity屬性android:excludeFromRencents="true"
炒俱。
4.IntentFilter
IntentFilter主要作用于Intent的隱式調(diào)用中。IntentFilter為Intent的隱式調(diào)用設(shè)置了過濾規(guī)則爪膊,如果不匹配將無法成功啟動目標(biāo)Activity权悟。IntentFilter中過濾的信息有action、category推盛、data峦阁。
一個Activity中可以有多個intent-filter,一個Intent只要能匹配任何一組intent-filter就可以成功啟動對應(yīng)的Activity耘成。
①action:action的匹配要求是Intent中的action存在且必須和過濾規(guī)則中的其中一個action相同榔昔,這里的相同指的是Intent中的action必須能夠和過濾規(guī)則中的action的字符串的值完全一樣。action區(qū)分大小寫瘪菌。
②category:Intent中如果含有category撒会,那么所有出現(xiàn)的category都必須和過濾規(guī)則中的其中一個category相同。(為了使Activity能接受到隱式調(diào)用师妙,必須在intent-filter中指定"android.intent.category.DEFAULT"這個category诵肛,以免在Intent未指定category時添加的默認(rèn)值無法匹配)
③data:data和action的匹配原則類似。由于data的結(jié)構(gòu)過于復(fù)雜且平時較少涉及到默穴,故此處不展開學(xué)習(xí)怔檩。
在action和category中,有一類action和category比較特別:
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
它們的共同作用標(biāo)明了這是一個入口Activity蓄诽,二者缺一不可薛训。
參考文獻(xiàn):
《第一行代碼——Android(第2版)》
《Android開發(fā)藝術(shù)探索》
《深入理解Android內(nèi)核設(shè)計(jì)思想》
若您覺得本文章對您有用,請您為我點(diǎn)上一顆小心心以表支持仑氛。感謝乙埃!