一絮识、Activity的LaunchMode
1. standard:標(biāo)準(zhǔn)模式,系統(tǒng)的默認(rèn)模式。
每次啟動(dòng)一個(gè)Activity都會(huì)重新創(chuàng)建一個(gè)新的實(shí)例(Activity的onCreate置媳、onStart于樟、onResume方法會(huì)被系統(tǒng)調(diào)用),不管這個(gè)實(shí)例是否已經(jīng)存在拇囊。在這種模式下迂曲,誰(shuí)啟動(dòng)了這個(gè)Activity,那么這個(gè)Activity就運(yùn)行在啟動(dòng)它的那個(gè)Activity所在的任務(wù)棧中寥袭。
比如路捧,同一應(yīng)用中,ActivityA啟動(dòng)了ActivityB(ActivityA是standard模式传黄,ActivityB是standard模式)杰扫,那么ActivityB就會(huì)進(jìn)入到ActivityA所在的任務(wù)棧中。
注意:當(dāng)我們用ApplictionContext去啟動(dòng)standard模式的Activity時(shí)膘掰,會(huì)報(bào)如下錯(cuò)誤:
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
這是因?yàn)閟tandard模式的Activity默認(rèn)會(huì)進(jìn)入啟動(dòng)它的Activity所屬的任務(wù)棧中章姓,而非Activity類型的Context(比如ApplicationContext)并沒(méi)有所謂的任務(wù)棧,因此出問(wèn)題识埋。
解決這個(gè)問(wèn)題的方法是為待啟動(dòng)的Activity指定FLAG_ACTIVITY_NEW_TASK標(biāo)記位凡伊,這樣啟動(dòng)的時(shí)候就會(huì)創(chuàng)建一個(gè)新的任務(wù)棧,這個(gè)時(shí)候待啟動(dòng)的Activity實(shí)際上是以singleTask模式啟動(dòng)的窒舟。
2. singleTop:棧頂復(fù)用模式系忙。
在這種模式下,如果新Activity已經(jīng)位于任務(wù)棧的棧頂惠豺,那么此Activity不會(huì)被重新創(chuàng)建银还,同時(shí)它的onNewIntent方法會(huì)被回調(diào)(Activity的onPause、onNewIntent洁墙、onResume方法會(huì)被系統(tǒng)調(diào)用)蛹疯,通過(guò)此方法的參數(shù)我們可以取出當(dāng)前請(qǐng)求的信息。
比如热监,同一應(yīng)用中捺弦,ActivityA啟動(dòng)了ActivityB(ActivityA是standard模式,ActivityB是singleTop模式)狼纬,那么ActivityB就會(huì)進(jìn)入到ActivityA所在的任務(wù)棧中,這個(gè)時(shí)候ActivityB再啟動(dòng)ActivityB骂际,由于ActivityA所在的任務(wù)棧中棧頂為ActivityB疗琉,因此不會(huì)再重新創(chuàng)建ActivityB實(shí)例,而是會(huì)回調(diào)棧頂ActivityB的onNewIntent方法歉铝。
3. singleTask:棧內(nèi)復(fù)用模式盈简。
這是一種單實(shí)例模式,在這種模式下,系統(tǒng)首先會(huì)尋找是否存在Activity想要的任務(wù)棧柠贤,
(1)如果不存在Activity想要的任務(wù)棧香浩,就創(chuàng)建一個(gè)任務(wù)棧,然后創(chuàng)建Activity實(shí)例并放入到棧中臼勉。
(2)如果存在Activity想要的任務(wù)棧邻吭,這時(shí)要看任務(wù)棧是否存在Activity實(shí)例,
(2.1)如果不存在Activity實(shí)例宴霸,就創(chuàng)建Activity實(shí)例并放入到棧中囱晴。
(2.2)如果存在Activity實(shí)例,系統(tǒng)就會(huì)把Activity上面的其它Activity全部出棧瓢谢,并回調(diào)其onNewIntent方法(Activity的onNewIntent畸写、onRestart、onStart氓扛、onResume方法會(huì)被系統(tǒng)調(diào)用)枯芬。
比如,同一應(yīng)用中采郎,ActivityA啟動(dòng)了ActivityB(ActivityA是singleTask模式千所,ActivityB是standard模式),那么ActivityB就會(huì)進(jìn)入到ActivityA所在的任務(wù)棧中尉剩,這個(gè)時(shí)候ActivityB再啟動(dòng)ActivityA真慢,由于ActivityA所在的任務(wù)棧中已經(jīng)存在ActivityA實(shí)例,因此不會(huì)再重新創(chuàng)建ActivityA實(shí)例理茎,而是將棧內(nèi)ActivityA上面的ActivityB出棧黑界,并回調(diào)ActivityA的onNewIntent方法。
4.singleInstance:?jiǎn)螌?shí)例模式
在這種模式下皂林,Activity實(shí)例只能單獨(dú)地存在于一個(gè)任務(wù)棧中朗鸠,后續(xù)的請(qǐng)求均不會(huì)創(chuàng)建新的Activity實(shí)例,除非這個(gè)獨(dú)特的任務(wù)棧被系統(tǒng)銷毀了础倍。
比如烛占,同一應(yīng)用中,ActivityA啟動(dòng)了ActivityB(ActivityA是singleInstance模式沟启,ActivityB是standard模式)忆家,那么ActivityB就不會(huì)進(jìn)入到ActivityA所在的任務(wù)棧中,系統(tǒng)會(huì)創(chuàng)建新的任務(wù)棧德迹,并創(chuàng)建ActivityB實(shí)例放入到新棧中芽卿,而ActivityA仍然單獨(dú)地存在于其所在的任務(wù)棧中。
情景分析:
有兩個(gè)任務(wù)棧胳搞,前臺(tái)任務(wù)棧1有兩個(gè)Activity卸例,分別為ActivityA(棧底称杨,standard模式)、ActivityB(棧頂筷转,standard模式)姑原,后臺(tái)任務(wù)棧2有兩個(gè)Activity,分別為ActivityX(棧底呜舒,singleTask模式)锭汛、ActivityY(棧頂,singleTask模式)阴绢,分以下兩個(gè)情況:
情況1. ActivityB去啟動(dòng)ActivityY店乐,
整個(gè)任務(wù)棧2會(huì)被切換到前臺(tái),即任務(wù)棧2顯示在任務(wù)棧1上面呻袭。連續(xù)按返回鍵則出棧順序?yàn)椋篈ctivityY眨八,ActivityX,ActivityB左电,ActivityA廉侧。
情況2. ActivityB去啟動(dòng)ActivityX,
任務(wù)棧2中ActivityY出棧篓足,剩下的任務(wù)棧全部被切換到前臺(tái)段誊,即任務(wù)棧2顯示在任務(wù)棧1上面。連續(xù)按返回鍵則出棧順序?yàn)椋篈ctivityX栈拖,ActivityB连舍,ActivityA。
TaskAffinity屬性:
可翻譯為任務(wù)相關(guān)性涩哟,這個(gè)參數(shù)標(biāo)識(shí)了一個(gè)Activity所需要的任務(wù)棧名字索赏,默認(rèn)情況下,所有Activity所需的任務(wù)棧名字為應(yīng)用的包名贴彼,當(dāng)然潜腻,我們可以為每一個(gè)Activity都單獨(dú)指定TaskAffinity屬性。
TaskAffinity屬性主要和singleTask模式和allowTaskReparenting屬性配合使用器仗,在其他情況下沒(méi)有意義融涣。分以下兩個(gè)情況:
情況1. 當(dāng)TaskAffinity屬性和singleTask模式配合使用時(shí),
待啟動(dòng)Activity會(huì)運(yùn)行在名字和TaskAffinity相同的任務(wù)棧中精钮。
情況2. 當(dāng)TaskAffinity屬性和allowTaskReparenting屬性配合使用時(shí)威鹿,
它允許allowTaskReparenting屬性為true的Activity重新回到名字和TaskAffinity相同的任務(wù)棧中。
比如轨香,應(yīng)用1有一個(gè)Activity(非主Activity)忽你,為ActivityA(standard模式,TaskAffinity屬性為應(yīng)用1包名)弹沽,應(yīng)用2有一個(gè)Activity(非主Activity)檀夹,為ActivityX(standard模式,TaskAffinity屬性為應(yīng)用2包名策橘,allowTaskReparenting屬性為true)炸渡。首先ActivityA啟動(dòng)ActivityX,系統(tǒng)會(huì)創(chuàng)建ActivityX實(shí)例并放到ActivityA實(shí)例所在的任務(wù)棧中丽已;然后按下home鍵蚌堵,在launch界面啟動(dòng)應(yīng)用2,這時(shí)顯示在前臺(tái)的是ActivityX而不是主Activity沛婴,即ActivityX從名字為應(yīng)用1包名的任務(wù)棧中轉(zhuǎn)移到了名字為應(yīng)用2包名的任務(wù)棧中吼畏。
二、Activity的Flags
FLAG_ACTIVITY_NEW_TASK
這個(gè)標(biāo)記位的作用是為Activity指定"singleTask"啟動(dòng)模式嘁灯。
FLAG_ACTIVITY_SINGLE_TOP
這個(gè)標(biāo)記位的作用是為Activity指定"singleTop"啟動(dòng)模式泻蚊。
FLAG_ACTIVITY_CLEAR_TOP
具有此標(biāo)記位的Activity,當(dāng)它啟動(dòng)時(shí)丑婿,在同一個(gè)任務(wù)棧中所有位于它上面的Activity都要出棧性雄,至于Activity自身是否出棧跟其啟動(dòng)模式有關(guān)系。
比如羹奉,同一應(yīng)用中秒旋,ActivityA啟動(dòng)了ActivityB(ActivityB是standard模式),那么ActivityB就會(huì)進(jìn)入到ActivityA所在的任務(wù)棧中诀拭,這時(shí)ActivityB啟動(dòng)ActivityA迁筛,并設(shè)置標(biāo)記位FLAG_ACTIVITY_CLEAR_TOP,分以下兩個(gè)情況:
情況1. 如果ActivityA是singleTask模式耕挨,
ActivityB會(huì)出棧细卧,ActivityA會(huì)回調(diào)onNewIntent方法(Activity的onNewIntent、onRestart俗孝、onStart酒甸、onResume方法會(huì)被系統(tǒng)調(diào)用)。
情況2. 如果ActivityA是standard模式赋铝,
ActivityB跟ActivityA都會(huì)出棧插勤,系統(tǒng)會(huì)重新創(chuàng)建ActivityA實(shí)例并放入棧中(Activity的onCreate、onStart革骨、onResume方法會(huì)被系統(tǒng)調(diào)用)农尖。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS(測(cè)試無(wú)效果)
具有這個(gè)標(biāo)記的Activity不會(huì)出現(xiàn)在歷史Activity的列表中,等同于android:excludeFromRecents="true"良哲。
三盛卡、指定啟動(dòng)模式
方式1:通過(guò)AndroidManifest指定
<activity android:name=".ActivityA"
android:launchMode="singleTask"/>
方式2:通過(guò)Intent設(shè)置標(biāo)志位指定
Intent intent = new Intent(MainActivity.this, ActivityA.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
兩種方式的區(qū)別:
以上兩種方式都可以為Activity指定啟動(dòng)模式,但是在優(yōu)先級(jí)上筑凫,方式2的優(yōu)先級(jí)要高于方式1滑沧,當(dāng)兩種方式同時(shí)存在時(shí)并村,以方式2為準(zhǔn)。
四滓技、查看任務(wù)棧
//命令
adb shell dumpsys activity
//log
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Running activities (most recent first):
TaskRecord{33bfcd5 #2209 A=com.tomorrow.androidtest8 U=0 sz=1}
Run #3: ActivityRecord{23fb6ed u0 com.tomorrow.androidtest8/.ActivityY t2209}
TaskRecord{951bcea #2208 A=com.tomorrow.androidtest7 U=0 sz=3}
Run #2: ActivityRecord{237f43b u0 com.tomorrow.androidtest8/.ActivityX t2208}
Run #1: ActivityRecord{6e79040 u0 com.tomorrow.androidtest7/.ActivityA t2208}
Run #0: ActivityRecord{5354310 u0 com.tomorrow.androidtest7/.MainActivity t2208}