標(biāo)準(zhǔn)Activity啟動(dòng)模式講解

任務(wù)棧是什么
任務(wù)棧Task擂啥,是一種用來(lái)放置Activity實(shí)例的容器悯辙,他是以棧的形式進(jìn)行盛放遗锣,也就是所謂的先進(jìn)后出货裹,主要有2個(gè)基本操作:壓棧和出棧,其所存放的Activity是不支持重新排序的精偿,只能根據(jù)壓棧和出棧操作更改Activity的順序弧圆。
啟動(dòng)一個(gè)Application的時(shí)候,系統(tǒng)會(huì)為它默認(rèn)創(chuàng)建一個(gè)對(duì)應(yīng)的Task笔咽,用來(lái)放置根Activity搔预。默認(rèn)啟動(dòng)Activity會(huì)放在同一個(gè)Task中,新啟動(dòng)的Activity會(huì)被壓入啟動(dòng)它的那個(gè)Activity的棧中叶组,并且顯示它拯田。當(dāng)用戶按下回退鍵時(shí),這個(gè)Activity就會(huì)被彈出棧甩十,按下Home鍵回到桌面船庇,再啟動(dòng)另一個(gè)應(yīng)用,這時(shí)候之前那個(gè)Task就被移到后臺(tái)侣监,成為后臺(tái)任務(wù)棧鸭轮,而剛啟動(dòng)的那個(gè)Task就被調(diào)到前臺(tái),成為前臺(tái)任務(wù)棧橄霉,Android系統(tǒng)顯示的就是前臺(tái)任務(wù)棧中的Top實(shí)例Activity窃爷。
任務(wù)棧的作用
以往基于應(yīng)用(application)的程序開(kāi)發(fā)中,程序具有明確的邊界姓蜂,一個(gè)程序就是一個(gè)應(yīng)用按厘,一個(gè)應(yīng)用為了實(shí)現(xiàn)功能可以采用開(kāi)辟新線程甚至新進(jìn)程來(lái)輔助,但是應(yīng)用與應(yīng)用之間不能復(fù)用資源和功能覆糟。而Android引入了基于組件開(kāi)發(fā)的軟件架構(gòu)刻剥,雖然我們開(kāi)發(fā)android程序,仍然使用一個(gè)apk工程一個(gè)Application的開(kāi)發(fā)形式滩字,但是對(duì)于Aplication的開(kāi)發(fā)就用到了Activity造虏、service等四大組件,其中的每一個(gè)組件麦箍,都是可以被跨應(yīng)用復(fù)用的漓藕,這就是android的神奇之處。雖然組件可以跨應(yīng)用被調(diào)用挟裂,但是一個(gè)組件所在的進(jìn)程必須是在組件所在的Aplication進(jìn)程中享钞。由于android強(qiáng)化了組件概念,弱化了Aplication的概念诀蓉,所以在android程序開(kāi)發(fā)中栗竖,A應(yīng)用的A組件想要使用拍照或錄像的功能就可以不用去針對(duì)Camera類進(jìn)行開(kāi)發(fā)暑脆,直接調(diào)用系統(tǒng)自帶的攝像頭應(yīng)用(稱其B應(yīng)用)中的組件(稱其B組件)就可以了,但是這就引發(fā)了一個(gè)新問(wèn)題狐肢,A組件運(yùn)行在A應(yīng)用中添吗,B組件運(yùn)行在B應(yīng)用中,自然都不在同一個(gè)進(jìn)程中份名,那么從B組件中返回的時(shí)候碟联,如何實(shí)現(xiàn)正確返回到A組件呢?Task就是來(lái)負(fù)責(zé)實(shí)現(xiàn)這個(gè)功能的僵腺,它是從用戶角度來(lái)理解應(yīng)用而建立的一個(gè)抽象概念鲤孵。因?yàn)橛脩羲芸吹降慕M件就是Activity,所以Task可以理解為實(shí)現(xiàn)一個(gè)功能而負(fù)責(zé)管理所有用到的Activity實(shí)例的棧辰如。
棧是一個(gè)先進(jìn)后出的線性表普监,根據(jù)Activity在當(dāng)前棧結(jié)構(gòu)中的位置,來(lái)決定該Activity的狀態(tài)丧没。正常情況下鹰椒,當(dāng)一個(gè)Activity啟動(dòng)了另一個(gè)Activity的時(shí)候锡移,新啟動(dòng)的Activity就會(huì)置于任務(wù)棧的頂端呕童,并處于活動(dòng)狀態(tài),而啟動(dòng)它的Activity雖然成功身退淆珊,但依然保留在任務(wù)棧中夺饲,處于停止?fàn)顟B(tài),當(dāng)用戶按下返回鍵或者調(diào)用finish()方法時(shí)施符,系統(tǒng)會(huì)移除頂部Activity往声,讓后面的Activity恢復(fù)活動(dòng)狀態(tài)牧牢。當(dāng)然作箍,世界不可能一直這么“和諧”,可以給Activity設(shè)置一些“特權(quán)”谴麦,來(lái)打破這種“和諧”的模式听哭,這種特權(quán)慢洋,就是通過(guò)在AndroidManifest文件中的屬性andorid:launchMode來(lái)設(shè)置或者通過(guò)Intent的flag來(lái)設(shè)置的,下面就先介紹下Activity的幾種啟動(dòng)模式陆盘。
standard
默認(rèn)模式普筹,可以不用寫(xiě)配置。在這個(gè)模式下隘马,都會(huì)默認(rèn)創(chuàng)建一個(gè)新的實(shí)例太防。因此,在這種模式下酸员,可以有多個(gè)相同的實(shí)例蜒车,也允許多個(gè)相同Activity疊加讳嘱。應(yīng)用場(chǎng)景:絕大多數(shù)Activity。

standard.png

如果以這種方式啟動(dòng)的Activity被跨進(jìn)程調(diào)用酿愧,在5.0之前新啟動(dòng)的Activity實(shí)例會(huì)放入發(fā)送Intent的Task的棧的頂部呢燥,盡管它們屬于不同的程序,這似乎有點(diǎn)費(fèi)解看起來(lái)也不是那么合理寓娩,所以在5.0之后叛氨,上述情景會(huì)創(chuàng)建一個(gè)新的Task,新啟動(dòng)的Activity就會(huì)放入剛創(chuàng)建的Task中棘伴,這樣就合理的多了寞埠。
singleTop
棧頂復(fù)用模式,如果要開(kāi)啟的activity在任務(wù)棧的頂部已經(jīng)存在焊夸,就不會(huì)創(chuàng)建新的實(shí)例仁连,而是調(diào)用 onNewIntent() 方法。避免棧頂?shù)腶ctivity被重復(fù)的創(chuàng)建阱穗。應(yīng)用場(chǎng)景:在通知欄點(diǎn)擊收到的通知饭冬,然后需要啟動(dòng)一個(gè)Activity,這個(gè)Activity就可以用singleTop揪阶,否則每次點(diǎn)擊都會(huì)新建一個(gè)Activity昌抠。當(dāng)然實(shí)際的開(kāi)發(fā)過(guò)程中,測(cè)試妹紙沒(méi)準(zhǔn)給你提過(guò)這樣的bug:某個(gè)場(chǎng)景下連續(xù)快速點(diǎn)擊鲁僚,啟動(dòng)了兩個(gè)Activity炊苫。如果這個(gè)時(shí)候待啟動(dòng)的Activity使用 singleTop模式也是可以避免這個(gè)Bug的。

2(1).png

同standard模式冰沙,如果是外部程序啟動(dòng)singleTop的Activity侨艾,在Android 5.0之前新創(chuàng)建的Activity會(huì)位于調(diào)用者的Task中,5.0及以后會(huì)放入新的Task中拓挥。
singleTask
棧內(nèi)復(fù)用模式唠梨, activity只會(huì)在任務(wù)棧里面存在一個(gè)實(shí)例。如果要激活的activity侥啤,在任務(wù)棧里面已經(jīng)存在当叭,就不會(huì)創(chuàng)建新的activity,而是復(fù)用這個(gè)已經(jīng)存在的activity愿棋,調(diào)用 onNewIntent() 方法科展,并且清空這個(gè)activity任務(wù)棧上面所有的activity。應(yīng)用場(chǎng)景:大多數(shù)App的主頁(yè)糠雨。對(duì)于大部分應(yīng)用才睹,當(dāng)我們?cè)谥鹘缑纥c(diǎn)擊回退按鈕的時(shí)候都是退出應(yīng)用,那么當(dāng)我們第一次進(jìn)入主界面之后,主界面位于棧底琅攘,以后不管我們打開(kāi)了多少個(gè)Activity垮庐,只要我們?cè)俅位氐街鹘缑妫紤?yīng)該使用將主界面Activity上所有的Activity移除的方式來(lái)讓主界面Activity處于棧頂坞琴,而不是往棧頂新加一個(gè)主界面Activity的實(shí)例哨查,通過(guò)這種方式能夠保證退出應(yīng)用時(shí)所有的Activity都能報(bào)銷毀。在跨應(yīng)用Intent傳遞時(shí)剧辐,如果系統(tǒng)中不存在singleTask Activity的實(shí)例寒亥,那么將創(chuàng)建一個(gè)新的Task,然后創(chuàng)建SingleTask Activity的實(shí)例荧关,將其放入新的Task中溉奕。
1:假如目前有個(gè)任務(wù)棧T1中的情況是ABC,這個(gè)時(shí)候ActivityD以singleTask模式請(qǐng)求啟動(dòng)忍啤,其所需要的任務(wù)棧正是T1加勤,則系統(tǒng)會(huì)直接創(chuàng)建D的實(shí)例并將其入棧到T1中。

singleTask1.png

2:假如DActivity啟動(dòng)所需要的任務(wù)棧為T(mén)2,由于T2和D的實(shí)例均不存在同波,那么系統(tǒng)會(huì)先創(chuàng)建任務(wù)棧T2鳄梅,然后再創(chuàng)建D的實(shí)例并將其入棧到T2中。我們可以通過(guò)設(shè)置Activity的taskAffinity屬性來(lái)模擬這一場(chǎng)景未檩。
<activity android:name=".SingleTaskActivity" android:label="singleTask launchMode" android:launchMode="singleTask" android:taskAffinity=""></activity>

singleTask2.png

3:如果D所需的任務(wù)棧為T(mén)3戴尸,并且當(dāng)前任務(wù)棧T3的情況為ADBC,根據(jù)棧內(nèi)復(fù)用的原則讹挎,此時(shí)D不會(huì)重新創(chuàng)建校赤,系統(tǒng)會(huì)把D切換到棧頂并調(diào)用其onNewIntent()方法,同時(shí)由于singleTask默認(rèn)具有ClearTop的效果筒溃,會(huì)導(dǎo)致棧內(nèi)所有在D上面的Activity全部出棧,于是最終T3的情況為AD沾乘。


singleTask3.png

4:假如目前有兩個(gè)任務(wù)棧怜奖,前臺(tái)任務(wù)棧T4的情況為AB,后臺(tái)任務(wù)棧t4里存有CD,假設(shè)CD的啟動(dòng)模式均為singleTask,現(xiàn)在由B去啟動(dòng)D,那么整個(gè)后臺(tái)任務(wù)都會(huì)被切換到前臺(tái)翅阵,這個(gè)時(shí)候整個(gè)棧就變成了ABCD歪玲。


singleTask4.png

5:假如上面的其他條件不變,B啟動(dòng)的是C而不是D,那么整個(gè)棧的情況就變成了ABC,因?yàn)镈在C上面掷匠,會(huì)被清理出棧滥崩。


singleTask5.png

singleInstance
單一實(shí)例模式,整個(gè)手機(jī)操作系統(tǒng)里面只有一個(gè)實(shí)例存在讹语。不同的應(yīng)用去打開(kāi)這個(gè)activity 共享公用的同一個(gè)activity钙皮。他會(huì)運(yùn)行在自己?jiǎn)为?dú),獨(dú)立的任務(wù)棧里面,并且任務(wù)棧里面只有他一個(gè)實(shí)例存在短条。應(yīng)用場(chǎng)景:呼叫來(lái)電界面导匣。這種模式的使用情況比較罕見(jiàn),在Launcher中可能使用茸时」倍ǎ或者你確定你需要使Activity只有一個(gè)實(shí)例。建議謹(jǐn)慎使用可都。

范冰冰.pic.jpg

設(shè)置Intent的Flag
系統(tǒng)提供了兩種方式來(lái)設(shè)置一個(gè)Activity的啟動(dòng)模式缓待,除了在AndroidManifest文件中設(shè)置以外,還可以通過(guò)Intent的Flag來(lái)設(shè)置一個(gè)Activity的啟動(dòng)模式渠牲,下面我們?cè)诤?jiǎn)單介紹下一些Flag命斧。
FLAG_ACTIVITY_NEW_TASK
使用一個(gè)新的Task來(lái)啟動(dòng)一個(gè)Activity,但啟動(dòng)的每個(gè)Activity都講在一個(gè)新的Task中嘱兼。該Flag通常使用在從Service中啟動(dòng)Activity的場(chǎng)景国葬,由于Service中并不存在Activity棧,所以使用該Flag來(lái)創(chuàng)建一個(gè)新的Activity棧芹壕,并創(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”效果相同。
FLAG_ACTIVITY_NO_HISTORY
Activity使用這種模式啟動(dòng)Activity睁壁,當(dāng)該Activity啟動(dòng)其他Activity后背苦,該Activity就消失了,不會(huì)保留在Activity棧中潘明。
LaunchMode與StartActivityForResult
我們?cè)陂_(kāi)發(fā)過(guò)程中經(jīng)常會(huì)用到StartActivityForResult方法啟動(dòng)一個(gè)Activity行剂,然后在onActivityResult()方法中可以接收到上個(gè)頁(yè)面的回傳值,但你有可能遇到過(guò)拿不到返回值的情況钳降,那有可能是因?yàn)锳ctivity的LaunchMode設(shè)置為了singleTask厚宰。5.0之后,android的LaunchMode與StartActivityForResult的關(guān)系發(fā)生了一些改變遂填。兩個(gè)Activity铲觉,A和B,現(xiàn)在由A頁(yè)面跳轉(zhuǎn)到B頁(yè)面吓坚,看一下LaunchMode與StartActivityForResult之間的關(guān)系:

before5.0.png

after5.0.png

這是為什么呢撵幽?
這是因?yàn)锳ctivityStackSupervisor類中的startActivityUncheckedLocked方法在5.0中進(jìn)行了修改。在5.0之前礁击,當(dāng)啟動(dòng)一個(gè)Activity時(shí)盐杂,系統(tǒng)將首先檢查Activity的launchMode逗载,如果為A頁(yè)面設(shè)置為SingleInstance或者B頁(yè)面設(shè)置為singleTask或者singleInstance,則會(huì)在LaunchFlags中加入FLAG_ACTIVITY_NEW_TASK標(biāo)志,而如果含有FLAG_ACTIVITY_NEW_TASK標(biāo)志的話况褪,onActivityResult將會(huì)立即接收到一個(gè)cancle的信息撕贞,而5.0之后這個(gè)方法做了修改,修改之后即便啟動(dòng)的頁(yè)面設(shè)置launchMode為singleTask或singleInstance测垛,onActivityResult依舊可以正常工作捏膨,也就是說(shuō)無(wú)論設(shè)置哪種啟動(dòng)方式,StartActivityForResult和onActivityResult()這一組合都是有效的食侮。所以如果你目前正好基于5.0做相關(guān)開(kāi)發(fā)号涯,不要忘了向下兼容,這里有個(gè)坑請(qǐng)注意避讓锯七。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末链快,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子眉尸,更是在濱河造成了極大的恐慌域蜗,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噪猾,死亡現(xiàn)場(chǎng)離奇詭異霉祸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)袱蜡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)丝蹭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人坪蚁,你說(shuō)我怎么就攤上這事奔穿。” “怎么了敏晤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵贱田,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我茵典,道長(zhǎng)湘换,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任统阿,我火速辦了婚禮,結(jié)果婚禮上筹我,老公的妹妹穿的比我還像新娘扶平。我一直安慰自己,他們只是感情好蔬蕊,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布结澄。 她就那樣靜靜地躺著哥谷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪麻献。 梳的紋絲不亂的頭發(fā)上们妥,一...
    開(kāi)封第一講書(shū)人閱讀 52,255評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音勉吻,去河邊找鬼监婶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛齿桃,可吹牛的內(nèi)容都是我干的惑惶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼短纵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼带污!你這毒婦竟也來(lái)了香到?” 一聲冷哼從身側(cè)響起鱼冀,我...
    開(kāi)封第一講書(shū)人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎悠就,沒(méi)想到半個(gè)月后千绪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡理卑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年翘紊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藐唠。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡帆疟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宇立,到底是詐尸還是另有隱情踪宠,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布妈嘹,位于F島的核電站柳琢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏润脸。R本人自食惡果不足惜柬脸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望毙驯。 院中可真熱鬧倒堕,春花似錦、人聲如沸爆价。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至骤宣,卻和暖如春秦爆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背憔披。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工等限, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人活逆。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓精刷,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蔗候。 傳聞我的和親對(duì)象是個(gè)殘疾皇子怒允,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容