Android基礎(chǔ)之Activity 運(yùn)行模式與回退棧

基本概念


LaunchMode 定義的是activity實(shí)例與task之間的關(guān)系,可以通過(guò)下面的兩種方式來(lái)定義:

  1. 使用manifest文件·

利用清單文件中的<activity>標(biāo)簽下的launchmode屬性留特。

  1. 使用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ō)明這種情況迹鹅。

diagram_backstack.png

使用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)摘抄

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市靡砌,隨后出現(xiàn)的幾起案子已脓,更是在濱河造成了極大的恐慌,老刑警劉巖通殃,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摆舟,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡邓了,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)媳瞪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)骗炉,“玉大人,你說(shuō)我怎么就攤上這事蛇受【淇” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵兢仰,是天一觀的道長(zhǎng)乍丈。 經(jīng)常有香客問(wèn)我,道長(zhǎng)把将,這世上最難降的妖魔是什么轻专? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮察蹲,結(jié)果婚禮上请垛,老公的妹妹穿的比我還像新娘。我一直安慰自己洽议,他們只是感情好宗收,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著亚兄,像睡著了一般混稽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上审胚,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天匈勋,我揣著相機(jī)與錄音,去河邊找鬼菲盾。 笑死颓影,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的懒鉴。 我是一名探鬼主播诡挂,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼碎浇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了璃俗?” 一聲冷哼從身側(cè)響起奴璃,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎城豁,沒(méi)想到半個(gè)月后苟穆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唱星,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年雳旅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片间聊。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡攒盈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哎榴,到底是詐尸還是另有隱情型豁,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布尚蝌,位于F島的核電站迎变,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏飘言。R本人自食惡果不足惜衣形,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望姿鸿。 院中可真熱鬧泵喘,春花似錦、人聲如沸般妙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)碟渺。三九已至鲜锚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間苫拍,已是汗流浹背芜繁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绒极,地道東北人骏令。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像垄提,于是被迫代替她去往敵國(guó)和親榔袋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子周拐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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