我們知道Activity的啟動(dòng)模式有四種分別為:standard(標(biāo)準(zhǔn)模式)、singleTop(棧頂復(fù)用模式)、singleTask(棧內(nèi)復(fù)用模式)和singleInstance(單一實(shí)例模式),在安卓系統(tǒng)中Activity通過(guò)任務(wù)棧的方式管理Activity痊夭,不同的啟動(dòng)模式實(shí)際上對(duì)應(yīng)的是對(duì)任務(wù)棧的不同操作决左,要想搞明白四種啟動(dòng)模式有什么不同,我們先來(lái)了解一下任務(wù)棧
一 任務(wù)棧
- 安卓系統(tǒng)通過(guò)任務(wù)棧來(lái)管理Activity
- 棧具有后進(jìn)先出的特性过咬,每次打開(kāi)一個(gè)Activity都會(huì)進(jìn)行壓棧操作,每次銷(xiāo)毀一個(gè)Activity都會(huì)進(jìn)行出棧操作
- 任何一個(gè)任務(wù)棧(task)都一定有一個(gè)taskAffinity值制妄,該值與該任務(wù)棧棧底的Acitivity的taskAffinity值相同
- 每個(gè)Activity都必須有一個(gè)taskAffinity值掸绞,如果沒(méi)有設(shè)置則該值等于application中的taskAffinity值,如果application中也沒(méi)有設(shè)置taskAffinity耕捞,則該值為包名
二 四種啟動(dòng)模式
Activity啟動(dòng)模式可以在Manifest.xml文件中通過(guò)launchMode屬性設(shè)置衔掸,也可以在代碼中通過(guò)添加Intent的Flag參數(shù)來(lái)設(shè)置
- standard(標(biāo)準(zhǔn)模式)
standard模式每次打開(kāi)Activity都會(huì)新建Activity實(shí)例,不管task(任務(wù)棧)中有沒(méi)有該Activity實(shí)例俺抽,舉個(gè)栗子:
ActivityA打開(kāi)ActivityB敞映,然后通過(guò)ActivityB打開(kāi)ActivityA,仍會(huì)再創(chuàng)建ActivityA的實(shí)例并放入棧中磷斧,此時(shí)棧的的結(jié)構(gòu)為A->B->A振愿;接著在ActivityA中再打開(kāi)ActivityA,則棧的結(jié)構(gòu)為:A->B->A->A弛饭;如果用戶(hù)想要回退則會(huì)關(guān)閉三次ActivityA冕末,體驗(yàn)十分不友好。 - singleTop(棧頂復(fù)用模式)
顧名思義如果一個(gè)Activity在棧頂孩哑,則需要再次打開(kāi)該Activity時(shí)不用新建該Activity實(shí)例而是調(diào)用該Activity的onNewIntent方法把新的intent傳遞過(guò)來(lái)栓霜,然后復(fù)用該Activity。如果該Activity不在棧頂還是會(huì)創(chuàng)建新的Activity實(shí)例横蜒,下面舉例說(shuō)明:
假設(shè)有三個(gè)Activity A胳蛮,B,C并且B的啟動(dòng)模式為singleTop
場(chǎng)景1:任務(wù)棧中只有A丛晌,此時(shí)A啟動(dòng)B仅炊。由于B并不在任務(wù)棧中,因此會(huì)創(chuàng)建B的實(shí)例并放入棧頂澎蛛,任務(wù)棧變?yōu)锳->B效果同standard
場(chǎng)景2:當(dāng)前任務(wù)棧結(jié)構(gòu)為A->B抚垄,此時(shí)再啟動(dòng)B。由于B已經(jīng)在任務(wù)棧中且位于棧頂,因此會(huì)調(diào)用B的onNewIntent方法呆馁,但不會(huì)新建B的實(shí)例桐经,任務(wù)棧結(jié)構(gòu)仍為A->B
場(chǎng)景3:當(dāng)前任務(wù)棧的結(jié)構(gòu)為A->B->C,此時(shí)再啟動(dòng)B浙滤。B雖然位于任務(wù)棧的中但不在棧頂阴挣,此時(shí)仍會(huì)創(chuàng)建B的實(shí)例并放入棧頂,任務(wù)棧變?yōu)锳->B->C->B
singleTop模式下仍會(huì)創(chuàng)建多個(gè)實(shí)例纺腊,如果想在同一個(gè)任務(wù)棧中只有一個(gè)實(shí)例畔咧,就需要使用singleTask模式了 - singleTask(棧內(nèi)復(fù)用模式)
如果一個(gè)Activity的啟動(dòng)模式為singleTask,當(dāng)啟動(dòng)這個(gè)Activity時(shí)揖膜,如果棧中已經(jīng)有了這個(gè)Activity實(shí)例誓沸,不管該Activity實(shí)例在棧中的什么位置都不會(huì)新建該Activity的實(shí)例,而是調(diào)用該Activity的onNewIntent方法并清空該Activity棧上面的其它Activity實(shí)例壹粟,從而讓該Activity位于棧頂拜隧。
假設(shè)有四個(gè)Activity A,B煮寡,C虹蓄,D并且B的啟動(dòng)模式為singleTask
場(chǎng)景1:當(dāng)前棧中只有A犀呼,此時(shí)打開(kāi)B幸撕,因?yàn)闂V袥](méi)有B的實(shí)例,所以會(huì)新建B的實(shí)例并放入棧頂外臂,而后棧的結(jié)構(gòu)為A->B
場(chǎng)景2:當(dāng)前棧的結(jié)構(gòu)為A->B-C-D坐儿,此時(shí)在D中打開(kāi)B,由于棧中已有B的實(shí)例宋光,所以不會(huì)新建B而是調(diào)用B的onNewIntent方法貌矿,并把B上面的Activity實(shí)例清空,而后棧的結(jié)構(gòu)為A->B罪佳;
一般應(yīng)用于App的主頁(yè)逛漫,從任何入口跳轉(zhuǎn)到主頁(yè)點(diǎn)擊返回都能夠退出App - singleInstance(單一實(shí)例模式)
設(shè)置為singleInstance的Activity具有全局唯一性,即在同一時(shí)刻安卓系統(tǒng)中僅存在一個(gè)該Activity實(shí)例赘艳,其它應(yīng)用復(fù)用該Activity實(shí)例
啟動(dòng)該Activity時(shí)如果該Activity實(shí)例尚不存在會(huì)在新的任務(wù)棧中創(chuàng)建該Activity實(shí)例酌毡,如果該Activity實(shí)例已經(jīng)存在則直接顯示該Activity實(shí)例
該Activity實(shí)例不與其它的Activity實(shí)例共存于同一個(gè)任務(wù)棧中,通過(guò)該Activity實(shí)例啟動(dòng)的其它Activity蕾管,只能在新的任務(wù)棧中創(chuàng)建實(shí)例枷踏。如果已經(jīng)存在與新啟動(dòng)的Activity的taskAffinity值相同的任務(wù)棧,則在該任務(wù)棧中創(chuàng)建新啟動(dòng)的Activity實(shí)例掰曾,否則就在一個(gè)新的任務(wù)棧中創(chuàng)建實(shí)例旭蠕。
三 LaunchMode與StartActivityForResult
在安卓開(kāi)發(fā)過(guò)程中我們常常使用startActivityForResult方法啟動(dòng)Activity并在onActivityResult方法中接收上個(gè)頁(yè)面返回的數(shù)據(jù),但你有可能遇到拿不到返回值的情況,可能是因?yàn)榇蜷_(kāi)的Activity的啟動(dòng)模式為singleTask掏熬。安卓5.0之后安卓的launchMode和onActivityResult發(fā)生了一些改變佑稠,假如Activity A 啟動(dòng)Activity B:
5.0以前
如果A的launchMode為singleInstance或者B的啟動(dòng)模式為singleTask或者singleInstance則A收不到返回?cái)?shù)據(jù);
5.0之后
不管A和B的啟動(dòng)模式是什么旗芬,A都可以收到B的返回?cái)?shù)據(jù)
四 通過(guò)設(shè)置intent的flag來(lái)設(shè)置啟動(dòng)模式
系統(tǒng)提供了兩種方式來(lái)設(shè)置啟動(dòng)模式讶坯,除了通過(guò)在Manifest.xml中設(shè)置還可以通過(guò)intent的Flag來(lái)設(shè)置,下面來(lái)介紹幾種Flag
- FLAG_ACTIVITY_NEW_TASK
這個(gè)Flag是我們平時(shí)見(jiàn)的最多的岗屏,使用一個(gè)新的task來(lái)啟動(dòng)一個(gè)Activity辆琅。該flag通常使用在從Service啟動(dòng)Activity的場(chǎng)景,因?yàn)樵赟ervice中并不存在task这刷,所以該flag用來(lái)創(chuàng)建一個(gè)新的task并在該task中創(chuàng)建Activity實(shí)例婉烟。 - FLAG_ACTIVITY_SINGLE_TOP
使用singletop模式啟動(dòng)一個(gè)Activity,與指定android:launchMode=“singleTop”效果相同暇屋。 - FLAG_ACTIVITY_CLEAR_TOP
使用SingleTask模式來(lái)啟動(dòng)一個(gè)Activity似袁,與指定android:launchMode=“singleTask”效果相同。
Activity啟動(dòng)模式就介紹完了咐刨,在實(shí)際開(kāi)發(fā)過(guò)程中選擇合適的啟動(dòng)模式可以解決一些復(fù)雜的問(wèn)題昙衅,例如:某個(gè)頁(yè)面不能重復(fù)打開(kāi),我們就可以設(shè)置其啟動(dòng)模式為singleTask定鸟。在明白啟動(dòng)模式的基礎(chǔ)上我們可以根據(jù)具體需求來(lái)選擇啟動(dòng)模式而涉。