Activity啟動(dòng)模式圖文詳解:standard, singleTop, singleTask 以及 singleInstance

這是一個(gè)針對(duì)技術(shù)開(kāi)發(fā)者的一個(gè)應(yīng)用畔濒,你可以在掘金上獲取最新最優(yōu)質(zhì)的技術(shù)干貨,不僅僅是Android知識(shí)锣咒、前端侵状、后端以至于產(chǎn)品和設(shè)計(jì)都有涉獵,想成為全棧工程師的朋友不要錯(cuò)過(guò)毅整!

英文原文:Understand Android Activity's launchMode: standard, singleTop, singleTask and singleInstance另外關(guān)于啟動(dòng)模式還有篇很好的文章:Android中Activity四種啟動(dòng)模式和taskAffinity屬性詳解

Activity是安卓上最聰明的設(shè)計(jì)之一趣兄,優(yōu)秀的內(nèi)存管理讓多任務(wù)完美運(yùn)行在最流行的操作系統(tǒng)之上。并不是讓Activity在屏幕上啟動(dòng)就完事了毛嫉,其啟動(dòng)方式也是需要關(guān)注的诽俯。這個(gè)話題的內(nèi)容很多,其中很重要的就是啟動(dòng)模式(launchMode)承粤。這也是我們這篇博客要討論的內(nèi)容。

因?yàn)椴煌腁ctivity有不同的目的闯团。有些被設(shè)計(jì)成每發(fā)送一個(gè)intent都單獨(dú)一個(gè)Activity工作辛臊,比如郵件客戶端中撰寫(xiě)郵件的Activity,而有些則被設(shè)計(jì)成單例的房交,比如郵件收件箱的Activity彻舰。

這就是為什么指明一個(gè)Activity是否需要新建還是使用現(xiàn)有Activity是很有必要的,否則可能導(dǎo)致糟糕的用戶體驗(yàn)。多虧了安卓的核心工程師刃唤,讓launchMode可以幫助你專門(mén)應(yīng)對(duì)這種情況隔心。

設(shè)置一個(gè)launchMode

一般地,我們可以直接在AndroidManifest.xml 標(biāo)簽的一個(gè)屬性中設(shè)置launchMode尚胞,如下:

android:name=".SingleTaskActivity"

android:label="singleTask?launchMode"

android:launchMode="singleTask">

有4種類型的launchMode硬霍,我們一個(gè)一個(gè)的看。

standard

這是默認(rèn)的模式笼裳。

這種模式下唯卖,當(dāng)Intent發(fā)送的時(shí)候,Activity總是被創(chuàng)建一個(gè)新的出來(lái)單獨(dú)工作躬柬。想象一下拜轨,如果有發(fā)送10個(gè)撰寫(xiě)郵件的Intent,那么將有10個(gè)不同的Activity啟動(dòng)允青。

Lollipop之前設(shè)備上的表現(xiàn)

這種Activity將被創(chuàng)建并置于棧頂橄碾,和發(fā)送intent的Activity處于同一個(gè)任務(wù)中。注:一般來(lái)講颠锉,安卓第三個(gè)虛擬鍵所列出的那些就是任務(wù)法牲。

下面的圖片顯示了向標(biāo)準(zhǔn)啟動(dòng)模式的Activity分享照片時(shí)的情況。雖然分別來(lái)自不同的應(yīng)用木柬,但仍然它會(huì)和發(fā)送intent的Activity處于同一個(gè)任務(wù)中皆串。

注:從圖中可以看出分享圖片的是Gallery應(yīng)用。

同時(shí)你會(huì)看到此時(shí)任務(wù)管理器是這樣的(有一點(diǎn)怪異)眉枕。

如果我們切換到另外一個(gè)應(yīng)用然后再切回到Gallery恶复,你會(huì)發(fā)現(xiàn)standard launchMode啟動(dòng)的Activity仍然在Gallery任務(wù)的上面,導(dǎo)致在操作Gallery之前速挑,我們必須首先結(jié)束這個(gè)額外的Activity谤牡。

Lollipop設(shè)備上的表現(xiàn)

如果Activity都是來(lái)自同一個(gè)應(yīng)用,其表現(xiàn)和Lollipop之前的設(shè)備一樣姥宝,在任務(wù)的頂端翅萤。

但是如果intent來(lái)自其他應(yīng)用,將創(chuàng)建一個(gè)新的任務(wù)腊满,同時(shí)新創(chuàng)建的Activity會(huì)被作為一個(gè)根Activity套么,如下:

注:圖片中的Task#2和Task#3分別表示兩個(gè)任務(wù),序號(hào)大的比序號(hào)小的后啟動(dòng)碳蛋。

下面是任務(wù)管理器中的樣子:

發(fā)生這種情況的原因是Lollipop中任務(wù)管理系統(tǒng)做了修改胚泌,讓它看起來(lái)更合理了。因?yàn)樗鼈冊(cè)诓煌娜蝿?wù)中肃弟,你可以直接切回Gallery玷室,你還可以觸發(fā)另一個(gè)Intent零蓉,創(chuàng)建新的與之前相同的任務(wù)。

撰寫(xiě)郵件的Activity或者發(fā)布社交網(wǎng)絡(luò)狀態(tài)的Activity都是采用這種Activity的例子穷缤。如果你希望Activity單獨(dú)服務(wù)于一個(gè)Intent敌蜂,就可以考慮standard啟動(dòng)模式。

singleTop

接下來(lái)就是singleTop模式津肛。它的表現(xiàn)幾乎和standard模式一模一樣章喉,一個(gè)singleTop Activity 的實(shí)例可以無(wú)限多,唯一的區(qū)別是如果在棧頂已經(jīng)有一個(gè)相同類型的Activity實(shí)例快耿,Intent不會(huì)再創(chuàng)建一個(gè)Activity囊陡,而是通過(guò)onNewIntent()被發(fā)送到現(xiàn)有的Activity。

在singleTop模式下我們需要同時(shí)在onCreate() 和 onNewIntent()中處理發(fā)來(lái)的intent掀亥,以滿足不同情況撞反。

這種啟動(dòng)模式的用例之一就是搜索功能。假設(shè)我們創(chuàng)建了一個(gè)搜索框搪花,點(diǎn)擊搜索的時(shí)候?qū)?dǎo)航到一個(gè)顯示搜索結(jié)果列表的SearchActivity中遏片,為了更好的用戶體驗(yàn),這個(gè)搜索框一般也會(huì)被放到SearchActivity中撮竿,這樣用戶想要再次搜索就不需要按返回鍵吮便。

想像一下,如果每次顯示搜索結(jié)果的時(shí)候我們都啟動(dòng)一個(gè)新的activity幢踏,10次搜索10個(gè)activity髓需,那樣當(dāng)我們想返回最初的那個(gè)activity的時(shí)候需要按10次返回。

所以我們應(yīng)該這樣房蝉,如果棧頂已經(jīng)有一個(gè)SearchActivity僚匆,我們將Intent發(fā)送給現(xiàn)有的activity,讓它來(lái)更新搜索結(jié)果搭幻。這樣就只會(huì)有一個(gè)在棧頂?shù)腟earchActivity咧擂,只需點(diǎn)一次back就可以回到之前的activity。

不管怎樣檀蹋,singleTop和它的調(diào)用者處在一個(gè)任務(wù)中松申。如果你想要讓intent發(fā)送給另一個(gè)任務(wù)中處于棧頂?shù)腁ctivity,是不行的俯逾。

而當(dāng)Intent來(lái)自于另外一個(gè)應(yīng)用的時(shí)候贸桶,新的Activity的啟動(dòng)方式和standard模式是一致的(pre-Lollipop:處于調(diào)用者任務(wù)的棧頂,Lollipop:會(huì)創(chuàng)建一個(gè)新的任務(wù))桌肴。

singleTask

這種模式和standard以及singleTop有很大不同刨啸。singleTask模式的Activity只允許在系統(tǒng)中有一個(gè)實(shí)例。如果系統(tǒng)中已經(jīng)有了一個(gè)實(shí)例识脆,持有這個(gè)實(shí)例的任務(wù)將移動(dòng)到頂部,同時(shí)intent將被通過(guò)onNewIntent()發(fā)送。如果沒(méi)有灼捂,則會(huì)創(chuàng)建一個(gè)新的Activity并置放在合適的任務(wù)中离例。

在同一個(gè)應(yīng)用中的情況

如果系統(tǒng)中還沒(méi)有singleTask的Activity,會(huì)新創(chuàng)建一個(gè)悉稠,并放在同一任務(wù)的棧頂宫蛆。

但是如果已經(jīng)存在,singleTask Activity上面的所有Activity將以合適的方式自動(dòng)銷毀的猛,讓我們想要顯示的Activity處于棧頂耀盗。同時(shí)Intent也會(huì)通過(guò)onNewIntent()方法發(fā)送到這個(gè)singleTask Activity。

在用戶體驗(yàn)方面卦尊,可能不是很合理叛拷,但是它就是這樣設(shè)計(jì)的...

你可能注意到了官方文檔中提到的一個(gè)問(wèn)題:

系統(tǒng)會(huì)創(chuàng)建一個(gè)新的任務(wù),并將這個(gè)Activity實(shí)例化為新任務(wù)的根部(root)岂却。

但從實(shí)驗(yàn)結(jié)果來(lái)看忿薇,并不是這么回事。singleTask Activity仍然在任務(wù)的Activity棧頂躏哩,我們可以從dumpsys activity 命令顯示上看出來(lái):

Taskid#239

TaskRecord{428efe30#239?A=com.thecheesefactory.lab.launchmode?U=0?sz=2}

Intent

{act=android.intent.action.MAIN?cat=[android.intent.category.LAUNCHER]

flg=0x10000000

cmp=com.thecheesefactory.lab.launchmode/.StandardActivity}

Hist#1:?ActivityRecord{429a88d0?u0?com.thecheesefactory.lab.launchmode/.SingleTaskActivity?t239}

Intent{cmp=com.thecheesefactory.lab.launchmode/.SingleTaskActivity}

ProcessRecord{4224313018965:com.thecheesefactory.lab.launchmode/u0a123}

Hist#0:?ActivityRecord{425fec98?u0?com.thecheesefactory.lab.launchmode/.StandardActivity?t239}

Intent

{act=android.intent.action.MAIN?cat=[android.intent.category.LAUNCHER]

flg=0x10000000

cmp=com.thecheesefactory.lab.launchmode/.StandardActivity}

ProcessRecord{4224313018965:com.thecheesefactory.lab.launchmode/u0a123}

如果你希望singleTask Activity表現(xiàn)的和文檔中描述的一致署浩,你需要為singleTask Activity設(shè)置taskAffinity屬性。

android:name=".SingleTaskActivity"

android:label="singleTask?launchMode"

android:launchMode="singleTask"

android:taskAffinity="">

這里是啟動(dòng)SingleTaskActivity的的結(jié)果(使用了taskAffinity之后)扫尺。

是否使用taskAffinity取決于你自己筋栋。

和其他應(yīng)用一起工作的情況

一旦intent是從另外的應(yīng)用發(fā)送過(guò)來(lái),并且系統(tǒng)中也沒(méi)有任何Activity的實(shí)例正驻,則會(huì)創(chuàng)建一個(gè)新的任務(wù)弊攘,并且新的Activity被作為根Activity創(chuàng)建。

除非擁有這個(gè)singleTask Activity 的應(yīng)用已經(jīng)存在拨拓,那樣的話肴颊,新建的Activity會(huì)置于這個(gè)任務(wù)的上面(而不是新建一個(gè)任務(wù))。

In case that there is an Activity instance existed?in any Task, the whole Task would be moved to top and every single Activity placed above the singleTask Activity will be destroyed with?lifecycle.If back button is pressed, user has to travel through the Activities in the stack before going back to the caller?Task.

假設(shè)已經(jīng)有了一個(gè)Activity的實(shí)例渣磷,不管它是在哪個(gè)任務(wù)中(包括上面的那種情況婿着,在用于這個(gè)Activity的應(yīng)用中),整個(gè)任務(wù)將被移到頂端醋界,而singleTask ?Activity上面的所有 Activity 都將被銷毀竟宋, 用戶需要按back鍵遍歷玩棧中的Activity才能回到調(diào)用者任務(wù)。

這種模式的應(yīng)用案例有形纺。郵件客戶端的收件箱或者社交網(wǎng)絡(luò)的時(shí)間軸丘侠。這些Activity一般不會(huì)設(shè)計(jì)成擁有多個(gè)實(shí)例,singleTask可以滿足逐样。但是在使用這種模式的時(shí)候必須要明智蜗字,因?yàn)橛行〢ctivity會(huì)在用戶不知情的情況下被銷毀打肝。

singleInstance

這個(gè)模式非常接近于singleTask,系統(tǒng)中只允許一個(gè)Activity的實(shí)例存在挪捕。區(qū)別在于持有這個(gè)Activity的任務(wù)中只能有一個(gè)Activity:即這個(gè)單例本身粗梭。If?another Activity is called from this kind of Activity, a new Task would be automatically created to place that new Activity. Likewise, if singleInstance Activity is called, new Task would be created to place the Activity.

不過(guò)結(jié)果卻很怪異,從dumpsys提供的信息來(lái)看级零,似乎系統(tǒng)中有兩個(gè)任務(wù)但任務(wù)管理器中只顯示一個(gè),即最后被移到頂部的那個(gè)断医。導(dǎo)致雖然后臺(tái)有一個(gè)任務(wù)在運(yùn)行,我們卻無(wú)法切換回去奏纪,這一點(diǎn)也不科學(xué)鉴嗤。

下面是當(dāng)singleInstance Activity被調(diào)用的同時(shí)棧中已經(jīng)有一些Activity的情況下所發(fā)生的事情:

本來(lái)有兩個(gè)任務(wù),但是任務(wù)管理器中卻只顯示一個(gè)任務(wù):

Since this Task could has only one Activity, we couldn't switch back to Task #1 anymore. Only?way to do so is to relaunch the application from launcher but it appears that the singleInstance Task would be hidden in the background instead.

因?yàn)檫@個(gè)任務(wù)只有一個(gè)Activity序调,我們?cè)僖矡o(wú)法切回到任務(wù)#1了醉锅。唯一的辦法是重新在launcher中啟動(dòng)這個(gè)應(yīng)用。?but之后的沒(méi)有翻譯炕置,因?yàn)槲乙膊幻靼鬃髡叩囊馑肌?/p>

不過(guò)這個(gè)問(wèn)題也有解決方案荣挨,就像我們?cè)趕ingleTask Acvity中做的,只要為singleInstance Activity設(shè)置taskAffinity屬性就可以了朴摊。

android:name=".SingleInstanceActivity"

android:label="singleInstance?launchMode"

android:launchMode="singleInstance"

android:taskAffinity="">

現(xiàn)在科學(xué)多了默垄。

這種模式很少被使用。實(shí)際使用的案例如Launcher的Activity或者100%確定只有一個(gè)Activity的應(yīng)用甚纲】诙В總之除非完全有必要,不然我不建議使用這種模式介杆。

Intent Flags

除了在AndroidManifest.xml中直接設(shè)置launch mode鹃操,我們還可以通過(guò)叫做Intent Flags的東西設(shè)置更多的行為,比如:

Intentintent=newIntent(StandardActivity.this,StandardActivity.class);

intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

startActivity(intent);

這段代碼將會(huì)啟動(dòng)一個(gè)singleTop啟動(dòng)模式的的StandardActivity春哨。

有許多種Flag可以使用荆隘,更多的請(qǐng)參考Intent

希望這篇文章對(duì)你有用赴背。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末椰拒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子凰荚,更是在濱河造成了極大的恐慌燃观,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件便瑟,死亡現(xiàn)場(chǎng)離奇詭異缆毁,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)到涂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)脊框,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)颁督,“玉大人,你說(shuō)我怎么就攤上這事缚陷∈矢荩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵箫爷,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我聂儒,道長(zhǎng)虎锚,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任衩婚,我火速辦了婚禮窜护,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘非春。我一直安慰自己柱徙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布奇昙。 她就那樣靜靜地躺著护侮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪储耐。 梳的紋絲不亂的頭發(fā)上羊初,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音什湘,去河邊找鬼长赞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛闽撤,可吹牛的內(nèi)容都是我干的得哆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼哟旗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼贩据!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起热幔,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤乐设,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后绎巨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體近尚,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年场勤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了戈锻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歼跟。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖格遭,靈堂內(nèi)的尸體忽然破棺而出哈街,到底是詐尸還是另有隱情,我是刑警寧澤拒迅,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布骚秦,位于F島的核電站,受9級(jí)特大地震影響璧微,放射性物質(zhì)發(fā)生泄漏作箍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一前硫、第九天 我趴在偏房一處隱蔽的房頂上張望胞得。 院中可真熱鬧,春花似錦屹电、人聲如沸阶剑。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)牧愁。三九已至,卻和暖如春葱色,著一層夾襖步出監(jiān)牢的瞬間递宅,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工苍狰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留办龄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓淋昭,卻偏偏與公主長(zhǎng)得像俐填,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子翔忽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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