該系列主要是記錄、回顧之前的學(xué)習(xí)和一些筆記惦积。
轉(zhuǎn)載請注明接校!
Activity在應(yīng)用中的表現(xiàn)為界面,它會加載指定的布局文件來顯示各種UI元素狮崩,同時蛛勉,用戶可以和這些UI元素進(jìn)行交互鹿寻。App便是由一個或多個Activity組成。
Activity生命周期
-
Activity的生命周期示意圖
image -
Activity生命周期包含最主要的7個生命周期函數(shù)诽凌,分別是onCreate(),onStart(),onResume(),onPause(),onStop(),onDestroy(),onRestart()毡熏。
- onCreate():在Activity第一次被創(chuàng)建的時候調(diào)用,并且在該方法中進(jìn)行Activity的初始化操作侣诵,如加載布局痢法、綁定事件。
- onStart():該方法在Activity由不可見變?yōu)榭梢姷臅r候調(diào)用窝趣。在Activity的onCreate()函數(shù)調(diào)用之后被調(diào)用疯暑,此時的Activity還處在不可見狀態(tài),當(dāng)Activity馬上可見時哑舒,onStart() 就會被調(diào)用妇拯。
- onResume():該方法在Activity變?yōu)榭梢姞顟B(tài),準(zhǔn)備好和用戶進(jìn)行交互的時候調(diào)用洗鸵,此時的Activity一定位于返回棧的棧頂越锈,并且處于運(yùn)行狀態(tài)。并且在執(zhí)行完該方法后膘滨,Activity就會請求AMS(AMS介紹)渲染它所管理的視圖甘凭。
- onPause():該方法在系統(tǒng)準(zhǔn)備啟動或恢復(fù)另一個Activity的時候調(diào)用。也就是當(dāng)Activity的狀態(tài)即將由可見狀態(tài)變?yōu)椴豢梢姞顟B(tài)時調(diào)用火邓。
- onStop():該方法在Activity完全不可見的時候調(diào)用丹弱。該方法與onPause()方法不同點(diǎn)在于,當(dāng)新啟動是一個對話框的Activity铲咨,那么onPause()會執(zhí)行躲胳,而onStop()不會。
- onDestroy():該方法會在Activity被銷毀之前調(diào)用纤勒,之后的Activity狀態(tài)將變?yōu)殇N毀狀態(tài)坯苹。一般Activity的內(nèi)存釋放也會在該時期進(jìn)行。
- onRestar():該方法會在Activity由Stop狀態(tài)變?yōu)镾tart狀態(tài)之前調(diào)用摇天。當(dāng)Activity由完全不見重新可以和用戶交互的時候會調(diào)用粹湃。
-
在Activity生命周期中,還有額外的兩個回調(diào)方法:onSaveInstanceState(),onRestoreInstanceState()泉坐。這兩個方法會在特定的時期被觸發(fā)为鳄。
- onSaveInstanceState():當(dāng)Activity有可能被銷毀,但是還沒有被銷毀時腕让,該Activity的onSaveInstanceState函數(shù)就會被執(zhí)行济赎,并且該方法會保存當(dāng)前Activity的狀態(tài)。除非該Activity是被用戶主動銷毀的记某,如當(dāng)用戶按back鍵時司训。例如:
- 用戶從當(dāng)前Activity切換到桌面;
- 長按Home鍵液南,選擇運(yùn)行其他的程序時壳猜;
- 按下電源鍵(關(guān)閉屏幕顯示)時;
- 從Activity A啟動一個新的Activity時滑凉;
- 屏幕方向切換時统扳,如從橫屏切換到豎屏;
- 電話打入等情況發(fā)生時畅姊;
- 總結(jié)一句話咒钟,一切讓當(dāng)前的Activity徹底在屏幕上看不見,但是沒有主動銷毀Activity的操作都會觸發(fā)該方法若未。
- onRestoreInstanceState():當(dāng)Activity確實(shí)被系統(tǒng)重新回收朱嘴,重新創(chuàng)建時才會調(diào)用。該方法可以取出onSaveInstanceState()方法保存的數(shù)據(jù)粗合,并用這些數(shù)據(jù)恢復(fù)之前Activity的狀態(tài)萍嬉。值得注意的一點(diǎn)是,在onSaveInstanceState()方法中保存的數(shù)據(jù)隙疚,我們可以在onCreate()和onSaveInstanceState()方法中獲取到壤追,這兩個方法的區(qū)別在于,onSaveInstanceState()方法一旦被調(diào)用供屉,就表明onSaveInstanceState()方法的Bundle參數(shù)一定是有值的啸盏,不需要做額外的null判斷驯妄。而onCreate()方法需要。
- onSaveInstanceState():當(dāng)Activity有可能被銷毀,但是還沒有被銷毀時腕让,該Activity的onSaveInstanceState函數(shù)就會被執(zhí)行济赎,并且該方法會保存當(dāng)前Activity的狀態(tài)。除非該Activity是被用戶主動銷毀的记某,如當(dāng)用戶按back鍵時司训。例如:
-
我們可以將Activity的完整的生命周期分為三個部分。
- 完整生存期(Activity在onCreate()方法和onDestroy()方法之間所經(jīng)歷過程)谭期。這兩個方法分別標(biāo)示Activity的創(chuàng)建和銷毀,并且在Activity整個生命周期中只會調(diào)用一次奠宜。
- 可見生存期(Activity在onStart()方法和onStop()方法之間所經(jīng)歷過程)跑杭。在該時期內(nèi),Activity總是可見的啡彬。這兩個方法會隨著用戶的操作可調(diào)用多次羹与。
- 前臺生存期(Activity在onResume(),onPause()方法之間所經(jīng)歷過程)庶灿。在該時期內(nèi)纵搁,Activity總是處于運(yùn)行狀態(tài),此時的活動是可以和用戶進(jìn)行交互的往踢。這兩個方法會隨著用戶的操作可調(diào)用多次腾誉。
-
特定操作的方法回調(diào):
- 第一次啟動(A)Activity,回調(diào):(A)onCreate()->(A)onStart()->(A)onResume();
- 用戶從(A)Activity打開新的(B)Activity,回調(diào)如下:(A)onPause()->(B)onCreate()->(B)onStart()->(B)onResume()->(A)onSaveInstanceState()->(A)onStop();
- 從(B)Activity返回(A)Activity,回調(diào)如下:(B)onPause()->(A)onRestart()->(A)onStart()->(A)onResume->(B)onStop()->(B)onDestroy();
- 用戶從(A)Activity打開一個透明主題或是Dialog形式的(B)Activity,回調(diào)如下:(A)onPause()->(B)onCreate()->(B)onStart()->(B)onResume();
- 從4.的(B)Activity返回(A)Activity利职,回調(diào)如下:(B)onPause()->(A)onResume()->(B)onStop()->(B)onDestroy();
- 按home鍵趣效,(A)Activity返回到桌面時,回調(diào)如下:(A)onPause()->(A)onSaveInstanceState()->(A)onStop();
- 從桌面返回(A)Activity時猪贪,回調(diào)如下:(A)onRestart()->(A)onStart()->(A)onResume;
- 按back鍵回退(A)Activity時跷敬,回調(diào)如下:(A)onPause()->(A)onStop()->(A)onDestroy();
-
異常情況下操作的方法回調(diào)
- 旋轉(zhuǎn)屏幕,使其重建Activity热押,回調(diào)如下:(A)onPause()->(A)onSaveInstanceState()->(A)onStop()->(A)onDestroy()->(重建的A)onCreate()->(重建的A)onStart()->(重建的A)onRestoreInstanceState()->(重建的A)onResume();
當(dāng)我們不想讓Activity在異常情況下重建西傀,該怎么辦?答案是給Activity指定configChanges屬性桶癣。在指定屬性后拥褂,當(dāng)Activity異常銷毀時便不再調(diào)用onSaveInstanceState()、onRestoreInstanceState()方法牙寞,取而代之會執(zhí)行onConfigurationChanged()方法饺鹃。
Activity的啟動模式
應(yīng)用程序都是由一個或多個Activity組成的,Activity的實(shí)例由Android內(nèi)部的任務(wù)棧來管理碎税。棧是一種先進(jìn)后出的集合尤慰。對于Android來說,當(dāng)前顯示的Activity必定位于棧頂雷蹂,當(dāng)按回退back鍵時伟端,棧頂?shù)腁ctivity便會被移除任務(wù)棧,位于被移除任務(wù)棧的Activity下面的Activity成為新的棧頂匪煌,同時顯示责蝠。
至于為什么需要劃分啟動模式,是為了更好地管理Activity萎庭,例如:當(dāng)我們只需要一個Activity只有一個實(shí)例霜医,那么啟動模式便可以幫助我們實(shí)現(xiàn)。
-
四種啟動模式
- standard(標(biāo)準(zhǔn)啟動模式)驳规,該模式也是Activity的默認(rèn)啟動模式肴敛。在該模式下,每次啟動一個Activity都會創(chuàng)建一個新的實(shí)例吗购,不管該Activity是否在任務(wù)棧中存在医男。同時,無論誰啟動該Activity捻勉,該Activity都會進(jìn)入啟動它的Activity所屬的任務(wù)棧镀梭。例如:棧A的Activity啟動了一個新的Activity,新的Activity會進(jìn)入棧A踱启。
- singleTop(棧頂復(fù)用模式)报账,該模式下啟動的Activity研底,會先判斷棧頂該Activity的實(shí)例是否存在,若存在透罢,則會重用位于棧頂?shù)膶?shí)例榜晦,并且會調(diào)用該實(shí)例的onNewIntent()方法將新的Intent對象傳遞到這個實(shí)例中。需要注意的是琐凭,在復(fù)用實(shí)例后芽隆,這個Activity的onCreate、onStart不會被重新調(diào)用统屈,而是調(diào)用的onNewIntent、onResume方法牙躺。如果新的Activity的實(shí)例不在棧頂愁憔,那么任然會創(chuàng)建新的Activity實(shí)例。
- singleTask(棧內(nèi)復(fù)用模式)孽拷,該模式下啟動Activity吨掌,那么棧內(nèi)只能存在一個該Activity的實(shí)例。創(chuàng)建該模式的Activity脓恕,首先會在棧內(nèi)尋找是否有實(shí)例膜宋,有的話會將該實(shí)例頂上的其他Activity移除任務(wù)棧(銷毀),讓該Activity位于棧頂炼幔;沒有的話則會創(chuàng)建一個實(shí)例并放在棧頂秋茫。
- singleInstance(單實(shí)例模式),加強(qiáng)版singleTask乃秀,該模式下的Activity只能單獨(dú)位于一個任務(wù)棧中肛著,這個任務(wù)棧也只會有這一個Activity。singleTask模式下的Activity可以擁有多個位于不同棧的實(shí)例跺讯,而singleInstance模式下的Activity就只有一個枢贿。
-
TaskAffinity和allowTaskReparenting
-
TaskAffinity是標(biāo)示Activity所需任務(wù)棧名字的參數(shù)。
- 在默認(rèn)情況下刀脏,Activity所需任務(wù)棧的名字為應(yīng)用的包名局荚。我們也能為每個Activity設(shè)置TaskAffinity屬性來自定義任務(wù)棧名,但是愈污,TaskAffinity屬性值不能與包名重復(fù)(要是重復(fù)還設(shè)置了干啥)耀态。
- TaskAffinity一般和singleTask啟動模式和allowTaskReparenting屬性搭配使用,其他情況下該屬性設(shè)置了也無用钙畔。
- 在一個包名為“A”的項(xiàng)目中茫陆,啟動一個TaskAffinity屬性為“B(B的結(jié)構(gòu)需要和包名類似,如“xxx.xxx.xxx”)”擎析,啟動模式為singleTask的Activity簿盅。該Activity首先會判斷名稱為“B”的任務(wù)棧是否存在挥下,存在的話在判斷是否有該Activity的實(shí)例,實(shí)例存在桨醋,則將該實(shí)例置于棧頂棚瘟;不存在則創(chuàng)建一個至于棧頂。若任務(wù)棧不存在喜最,則創(chuàng)建任務(wù)棧偎蘸,再創(chuàng)建實(shí)例。
allowTaskReparenting屬性常用于和TaskAffinity屬性搭配使用瞬内,主要功能界定是棧A中的Activity是否能遷移到棧B中去迷雪,而遷移跟Activity的TaskAffinity有關(guān)。舉個栗子:應(yīng)用A有甲Activity虫蝶,應(yīng)用B有乙Activity章咧,應(yīng)用A啟動應(yīng)用B的乙。這時能真,應(yīng)用A的棧中有甲乙兩個Activity赁严,按home回到桌面,啟動應(yīng)用B粉铐,這時會發(fā)現(xiàn)疼约,應(yīng)用A的棧中的乙去到了應(yīng)用B的棧。當(dāng)然蝙泼,這是allowTaskReparenting屬性為true的情況程剥,如果為false,則應(yīng)用A的棧不變踱承,應(yīng)用B的棧內(nèi)會重新生成一個新的乙倡缠。
大佬博客更詳細(xì)描寫
-
-
啟動模式的設(shè)置
-
通過AndroidMenifest為Activity指定啟動模式:
<activity android:name=".Activity_A" android:launchMode="singleTask" android:allowTaskReparenting="flase" android:taskAffinity="com.angki.a"/> android:launchMode: 設(shè)置啟動模式 android:taskAffinity:設(shè)置taskAffinity android:allowTaskReparenting:設(shè)置allowTaskReparenting
-
通過在Intent設(shè)置標(biāo)志位來指定啟動模式:
Intent intent = new Intent(MainActivity.this, Activity_A.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);
兩種啟動方式的區(qū)別,第二種優(yōu)先級高于第一種茎活,當(dāng)兩種方式同時存在時昙沦,以第二種方式為準(zhǔn)。
-
-
常用標(biāo)記位
- FLAG_ACTIVITY_NEW_TASK载荔,新建一個Task來啟動Activity盾饮,和清單文件指定SingleTask啟動模式效果相同。
- FLAG_ACTIVITY_SINGLE_TOP懒熙,和清單文件指定SingleTop啟動模式效果相同丘损。
- FLAG_ACTIVITY_CLEAR_TOP,清除該啟動Activity同棧中所有位于它上面的Activity工扎,和清單文件指定SingleTask啟動模式效果相同徘钥。
- FLAG_ACTIVITY_NO_HISTORY,以該模式啟動的Activity在啟動其他Activity會自己銷毀自己肢娘。
- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS呈础,使用該模式啟動的Activity不添加到最近應(yīng)用列表舆驶,與屬性android:excludeFromRecents="true"效果相同。需要注意的是而钞,要想應(yīng)用列表不顯示該Activity沙廉,需要一個不同的棧來存放。因?yàn)樵搼?yīng)用列表不顯示是把該Activity所在任務(wù)棧置于后臺任務(wù)棧臼节。舉個例子:
AB兩個Activity同在一個棧內(nèi)撬陵,其中B為FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS模式啟動的。當(dāng)前頁面顯示B頁面网缝,點(diǎn)擊多任務(wù)管理按鍵巨税,發(fā)現(xiàn)顯示的仍是B頁面。
-
Main途凫、A兩個Activity不在一個棧內(nèi)垢夹,其中A為FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS模式啟動的。查看棧顯示:
Running activities (most recent first): TaskRecord{2becf13d #7042 A=com.angki.task U=0 sz=1} Run #1: ActivityRecord{18df41f7 u0 com.angki.androidlearn/.Activity_A t7042} TaskRecord{3c3ba83 #7041 A=com.angki.androidlearn U=0 sz=1} Run #0: ActivityRecord{2d080907 u0 com.angki.androidlearn/.MainActivity t7041}
點(diǎn)擊點(diǎn)擊多任務(wù)管理按鍵:
Running activities (most recent first): TaskRecord{3c3ba83 #7041 A=com.angki.androidlearn U=0 sz=1} Run #1: ActivityRecord{2d080907 u0 com.angki.androidlearn/.MainActivity t7041} TaskRecord{2becf13d #7042 A=com.angki.task U=0 sz=1} Run #0: ActivityRecord{18df41f7 u0 com.angki.androidlearn/.Activity_A t7042}
可以發(fā)現(xiàn)维费,A的棧置于后,當(dāng)前顯示的是Main頁面促王。
ABC三個Activity犀盟,A屬于棧a,BC屬于棧b蝇狼,其中B為FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS模式啟動的阅畴。當(dāng)前顯示C頁面,點(diǎn)擊點(diǎn)擊多任務(wù)管理按鍵迅耘,當(dāng)前顯示A頁面贱枣,說明棧b被后置。按下back鍵颤专,頁面顯示C頁面纽哥,再按下back鍵,頁面顯示B頁面栖秕,再按下back鍵春塌,退出程序。