基本概念
LaunchMode 定義的是activity實(shí)例與task之間的關(guān)系,可以通過(guò)下面的兩種方式來(lái)定義:
-
使用manifest文件·
利用清單文件中的<activity>標(biāo)簽下的launchmode屬性留特。
-
使用intent flags
調(diào)用startActivity(),在intent中指定flag盈简。
在Activity A中啟動(dòng)B剃根,可以利用Activity B在清單中的launchmode定義,也可以在A中調(diào)用startActivity()的時(shí)候通過(guò)intent的flag傳入,當(dāng)兩種方式都有定義,intent的flag參數(shù)會(huì)覆蓋掉B原有的定義。
使用manifest文件
利用Activity 元素的launchMode屬性
launchMode屬性指定Activity如何被運(yùn)行到一個(gè)task中陋桂。launchMode的值有四種:
"standard" (the default mode)
默認(rèn), 每次啟動(dòng)Activity系統(tǒng)都會(huì)產(chǎn)生一個(gè)新的實(shí)例蝶溶,并且把intent發(fā)送給新產(chǎn)生的實(shí)例嗜历,這個(gè)Activity可以被實(shí)例化多次,每個(gè)實(shí)例可以屬于不同的task抖所,每個(gè)task也可以保有多個(gè)此Activity的實(shí)例梨州。
"singleTop"
如果當(dāng)前task 的回退棧棧頂已經(jīng)存在一個(gè)此Activity的實(shí)例,系統(tǒng)通過(guò)調(diào)用這個(gè)實(shí)例的onNewIntent()方法把intent發(fā)送給這個(gè)Activity實(shí)例田轧,而不是創(chuàng)建一個(gè)新的此Activity的實(shí)例暴匠。這個(gè)Activity也可以被實(shí)例化多次,每個(gè)實(shí)例可以屬于不同的task傻粘,每個(gè)task可一個(gè)保有多個(gè)實(shí)例(僅限于此Activity已存在的實(shí)例不在棧頂)
注意:
應(yīng)用場(chǎng)合如下:不想出現(xiàn)2個(gè)同樣的activity在頂部巷查。比如用戶(hù)正在一個(gè)activity閱讀信息,這時(shí)來(lái)了notification抹腿,用戶(hù)點(diǎn)擊后應(yīng)該更新這些信息,而不是新建一個(gè)activity旭寿,這樣在點(diǎn)擊back時(shí)警绩,就不會(huì)出現(xiàn)回到舊信息activity的情況了。這種情況正是下面這段英語(yǔ)提到的盅称。
Note: When a new instance of an activity is created, the user can press the Back button to return to the previous activity. But when an existing instance of an activity handles a new intent, the user cannot press the Back button to return to the state of the activity before the new intent arrived in onNewIntent()
.
例如肩祥,當(dāng)前回退棧中有A后室,B,C混狠,D四個(gè)Activity岸霹,全部是Standard,在D中調(diào)用startActivity()去啟動(dòng)B将饺,intent的flag設(shè)置成FLAG_ACTIVITY_CLEAR_TOP 和FLAG_ACTIVITY_NEW_TASK贡避,系統(tǒng)發(fā)現(xiàn)棧中有B,會(huì)先銷(xiāo)毀這個(gè)B予弧,再原位置重建B刮吧,清空CD,而不是把這個(gè)新建的B的實(shí)例壓入棧頂掖蛤,這里之所以會(huì)銷(xiāo)毀B再新建B杀捻,因?yàn)锽的launchmode是Standard,無(wú)論什么情況下啟動(dòng)蚓庭,都需要new一個(gè)B的實(shí)例致讥,但如果此時(shí)B是SingleTop的,系統(tǒng)會(huì)把這個(gè)intent通過(guò)onNewIntent傳給已經(jīng)在棧中的B的實(shí)例器赞,不需要銷(xiāo)毀再創(chuàng)建垢袱,仍需要清空CD。
"singleTask"
系統(tǒng)會(huì)創(chuàng)建一個(gè)新的task并且把這個(gè)實(shí)例放在棧底(此處有疑問(wèn)拳魁,測(cè)試發(fā)現(xiàn)并不一定是棧底)惶桐,但是,如果在一個(gè)單獨(dú)的task中已經(jīng)存在一個(gè)此Activity的實(shí)例潘懊,系統(tǒng)會(huì)把intent通過(guò)onNewIntent()發(fā)送給這個(gè)實(shí)例(測(cè)試發(fā)現(xiàn)如果在回退棧中姚糊,該Activity的上面還有其他Activity,啟動(dòng)此Activity會(huì)清空棧中此Activity上面的其他Activity)授舟,而不是創(chuàng)建一個(gè)新的實(shí)例救恨。同一時(shí)間在只有一個(gè)此Activity的實(shí)例存在于系統(tǒng)中。
"singleInstance"
與SingleTask一樣释树,不同的是SingleTask的Activity所在的task中可以有其他的Activity肠槽,而SingleInstance的Activity獨(dú)占一個(gè)task,并且在整個(gè)系統(tǒng)中只有唯一的一個(gè)實(shí)例奢啥。由這個(gè)Activity啟動(dòng)的其他Activity都會(huì)在新的task中打開(kāi)秸仙。
另一個(gè)例子,系統(tǒng)自帶瀏覽器APP把瀏覽器Activity聲明為SingleTask桩盲,通過(guò)在Activity標(biāo)簽里的launchMode進(jìn)行指定寂纪,這意味著如果你發(fā)送一個(gè)intent啟動(dòng)瀏覽器,不管是為瀏覽器新開(kāi)啟一個(gè)task還是從瀏覽器已經(jīng)在后臺(tái)保有的task中啟動(dòng)瀏覽器,瀏覽器Activity與你的APP不在同一個(gè)task捞蛋。
不管一個(gè)Activity是不是在一個(gè)新的task中啟動(dòng)孝冒,點(diǎn)擊返回都會(huì)返回前一個(gè)Activity。不過(guò)拟杉,如果啟動(dòng)一個(gè)LaunchMode為singleTask的Activity庄涡,如果該Activity此時(shí)在一個(gè)處于后臺(tái)的task中,整個(gè)task會(huì)變成前臺(tái)task搬设,此時(shí)穴店,回退棧會(huì)包含由這個(gè)后臺(tái)task攜帶過(guò)來(lái)所有Activity,放在回退棧的棧頂焕梅,下圖說(shuō)明這種情況迹鹅。
使用intent flags
FLAG_ACTIVITY_NEW_TASK
在一個(gè)新的task里啟動(dòng)Activity. 如果已經(jīng)有Activity實(shí)例運(yùn)行在某一task中,啟動(dòng)這個(gè)Activity會(huì)把該實(shí)例所在的task帶到前臺(tái)贞言,由該實(shí)例的onNewIntent()來(lái)接收新的intent斜棚。
FLAG_ACTIVITY_SINGLE_TOP
如果被啟動(dòng)的Activity就是當(dāng)前的Activity,這個(gè)已經(jīng)存在的實(shí)例通過(guò)onNewIntent()接收intent该窗,不會(huì)產(chǎn)生新的實(shí)例弟蚀。
FLAG_ACTIVITY_CLEAR_TOP
被啟動(dòng)的Activity如果已經(jīng)存運(yùn)行于當(dāng)前task,回退棧中所有在此Activity上面的Activity都將被銷(xiāo)毀酗失,此Activity通過(guò)onNewIntent()接收新的intent义钉。
例如,一個(gè)task中有A规肴,B捶闸,C,D拖刃,四個(gè)Activity删壮,如果D 調(diào)用startActivtiy()啟動(dòng)Activity B,C和D會(huì)被銷(xiāo)毀兑牡,B接收這個(gè)intent央碟,回退棧中有A,B均函。
上例中的Activity B的實(shí)例亿虽,或者通過(guò)onNewIntent()接收新的intent,或者銷(xiāo)毀新建來(lái)處理新的intent苞也。如果B的launchmode是standard洛勉,并且沒(méi)有設(shè)置FLAG_ACTIVITY_SINGLE_TOP,那么B會(huì)被銷(xiāo)毀重啟如迟,如果是其他launchmode或者設(shè)置了FLAG_ACTIVITY_SINGLE_TOP收毫,則會(huì)通過(guò)onNewIntent()接收。
FLAG_ACTIVITY_CLEAR_TOP 和FLAG_ACTIVITY_NEW_TASK結(jié)合使用會(huì)有個(gè)不錯(cuò)的效果。
如果啟動(dòng)的Activity位于task的底部牛哺,它會(huì)把所在task帶到前臺(tái),并且清理狀態(tài)至root狀態(tài)劳吠,當(dāng)從通知欄里打開(kāi)一個(gè)Activity的會(huì)非常有用引润。
處理Affinity(此后的文本翻譯自google文檔)
Affinity指的是一個(gè)Activity偏向于從屬于哪個(gè)task,默認(rèn)情況下痒玩,一個(gè)APP內(nèi)的所有Activity互相之間共享一個(gè)affinity的值淳附,所以,所有同一APP下的所有Activity都偏向于從屬于同一個(gè)task蠢古。但是奴曙,這個(gè)值是可以更改的,不同APP內(nèi)的Activity可以共享一個(gè)affinity草讶,同一個(gè)APP內(nèi)的Activity也可以被分配不同的affinity的值洽糟。
affinity的值可以通過(guò)修改Activity標(biāo)簽的taskAffinity屬性來(lái)修改。
這個(gè)屬性接收一個(gè)String的值堕战,必須在manifest標(biāo)簽范圍內(nèi)是唯一的值坤溃,因?yàn)橄到y(tǒng)是通過(guò)名稱(chēng)來(lái)標(biāo)識(shí)APP的affinity的值的。
Affinity作用于以下兩種情況:
- 啟動(dòng)Activity的intent中包含 FLAG_ACTIVITY_NEW_TASK 的flag
通過(guò)startActivity()啟動(dòng)一個(gè)新的Activity時(shí)嘱丢,默認(rèn)情況下薪介,新的Activity會(huì)被壓入與啟動(dòng)者相同的回退棧中。但是越驻,如果在啟動(dòng)Activity的時(shí)候汁政,使用了FLAG_ACTIVITY_NEW_TASK 這個(gè)標(biāo)志,系統(tǒng)會(huì)為新的Activity尋找一個(gè)新的task缀旁。通常情況下记劈,是一個(gè)新的task。但是也并不是必須的诵棵。如果系統(tǒng)中有一個(gè)task的affinity值與新的Activity的值相同抠蚣,新的Activity會(huì)被分配到這個(gè)task中。如果沒(méi)有這樣的task履澳,就啟動(dòng)一個(gè)新的task嘶窄。如果這個(gè)標(biāo)志產(chǎn)生了一個(gè)新的task,當(dāng)用戶(hù)點(diǎn)擊home鍵離開(kāi)的時(shí)候距贷,必須要有某種方式能夠使用戶(hù)返回到這個(gè)task來(lái)柄冲。有些實(shí)體(例如通知管理器)總是從一個(gè)外部task中啟動(dòng)Activity,所以在通過(guò)startActivity()啟動(dòng)新的Activity時(shí)總是需要傳遞FLAG_ACTIVITY_NEW_TASK 這個(gè)標(biāo)志忠蝗。如果你有一個(gè)Activity可以被外部實(shí)體可能這個(gè)標(biāo)志啟動(dòng)现横,注意用戶(hù)可以有一種獨(dú)立的方式回到啟動(dòng)它的task,例如點(diǎn)擊啟動(dòng)圖標(biāo)。
- 當(dāng)Activity的allowTaskReparenting的值為true
這種情況下戒祠,一個(gè)Activity可以動(dòng)啟動(dòng)它的那個(gè)task移動(dòng)到它的affinity值對(duì)應(yīng)的task中骇两,當(dāng)那個(gè)task回到前臺(tái)。例如姜盈,假設(shè)低千,一個(gè)報(bào)告指定城市天氣情況的Activity作為一個(gè)旅行APP的一部分,它跟其他處在同一APP的Activity一樣有一個(gè)相同的affinity值馏颂,并且允許通過(guò)這個(gè)屬性來(lái)調(diào)整目標(biāo)task示血。當(dāng)你的一個(gè)Activity啟動(dòng)了這個(gè)天氣預(yù)報(bào)Activity,它默認(rèn)跟你的Activity在一個(gè)task里救拉,但是难审,當(dāng)旅行APP進(jìn)入到前臺(tái),這個(gè)天氣預(yù)報(bào)Activity又會(huì)被重新分配給旅行APP并且在旅行APP內(nèi)展示亿絮。
提示:
如果一個(gè)APK文件從用戶(hù)的角度看是多款A(yù)PP告喊,可能需要這個(gè)屬性來(lái)設(shè)置不同的affinity來(lái)關(guān)聯(lián)不同的APP。
清理回退棧
如果用戶(hù)離開(kāi)一個(gè)task太長(zhǎng)時(shí)間壹无,系統(tǒng)會(huì)清除task中的所有Activity僅僅保留這下根Activity葱绒。當(dāng)用戶(hù)返回到這個(gè)task的時(shí)候,只有這個(gè)根Activity會(huì)被恢復(fù)斗锭。系統(tǒng)通過(guò)這種方式來(lái)處理地淀,是因?yàn)榻?jīng)過(guò)相當(dāng)長(zhǎng)的一段時(shí)間之后,用戶(hù)已經(jīng)拋棄他們?cè)?jīng)正在做的事情岖是,計(jì)劃再回來(lái)的時(shí)候做點(diǎn)新的事情帮毁。
你可以通過(guò)如下屬性來(lái)更改這種行為:
- alwaysRetainTaskState
根Activity此屬性設(shè)置為true的時(shí)候,會(huì)保留回退棧中所有Activity的狀態(tài)豺撑。 - clearTaskOnLaunch
根Activity此屬性設(shè)置為true的時(shí)候烈疚,不管離開(kāi)應(yīng)用多久,回退棧中的Activity都會(huì)被清理聪轿,與alwaysRetainTaskState的情況相反爷肝。 - finishOnTaskLaunch
類(lèi)似于clearTaskOnLaunch,但是它作用于單個(gè)Activity陆错,而不是針對(duì)整個(gè)Task灯抛。它可以清理任意一個(gè)Activity,包含根Activity音瓷。設(shè)置為true的時(shí)候对嚼,只有在當(dāng)前的會(huì)話中會(huì)保留此Activity,只要用戶(hù)離開(kāi)绳慎,再次回來(lái)的時(shí)候纵竖,此Activity就會(huì)被清理漠烧。
參考文獻(xiàn):
Tasks and Back Stack
<activity>
Android 閱讀Tasks and Back Stack文章后的重點(diǎn)摘抄