詳解Activity啟動(dòng)模式(二)Activity的四種啟動(dòng)模式——LaunchMode

四種啟動(dòng)模式

Standard

標(biāo)準(zhǔn)模式,每當(dāng)有一次Intent請求员凝,就會(huì)創(chuàng)建一個(gè)新的Activity實(shí)例。

  • Android 5.0 之前

    1. 同一應(yīng)用內(nèi)

    新生成的Activity会放,放入發(fā)送Intent者Task的棧頂监氢。

      ```
    

TaskRecord{537925a8 #42 A com.zlq.lmt U 0}
Run #3: ActivityRecord{538314d0 com.zlq.lmt/.StandardActivity}
Run #2: ActivityRecord{5385a7c4 com.zlq.lmt/.StandardActivity}
Run #1: ActivityRecord{53760908 com.zlq.lmt/.MainActivity}


    2. 跨應(yīng)用啟動(dòng)
    
    新生成的Activity,放入發(fā)送Intent者Task的棧的棧頂(盡管他們屬于不同的程序管闷,還是會(huì)放入調(diào)用者程序的棧內(nèi))。

      ```
TaskRecord{537df318 #52 A com.zlq.bbb U 0}
      Run #2: ActivityRecord{537a889c com.zlq.lmt/.StandardActivity}
      Run #1: ActivityRecord{537a4a5c com.zlq.bbb/.MainActivityB}

這時(shí)窃肠,我們打開任務(wù)管理器(最近任務(wù)按鈕)包个。會(huì)發(fā)現(xiàn)最近任務(wù)中現(xiàn)實(shí)的應(yīng)用名為B應(yīng)用,展示的界面卻是A應(yīng)用的StandardActivity(因?yàn)槠湮挥赥ask棧頂)冤留。


跨應(yīng)用啟動(dòng)Standard Activity
跨應(yīng)用啟動(dòng)Standard Activity
  • Android 5.0 之后

    1. 同一應(yīng)用內(nèi)
      與Android 5.0之前保持一致
    2. 跨應(yīng)用啟動(dòng)
      經(jīng)檢驗(yàn)與Android5.0之前保持一致碧囊。Android6.0上也依然沒改變树灶。參考資料深入講解Android中Activity launchMode內(nèi)容或許有誤 。
  • 使用場景
    standard這種啟動(dòng)模式適合于撰寫郵件Activity或者社交網(wǎng)絡(luò)消息發(fā)布Activity糯而。如果你想為每一個(gè)intent創(chuàng)建一個(gè)Activity處理天通,那么就是用standard這種模式。

SingleTop

棧頂復(fù)用模式. SingleTop其實(shí)和Standard幾乎一樣歧蒋,使用SingleTop的Activity也可以創(chuàng)建很多個(gè)實(shí)例土砂。唯一不同的就是州既,如果調(diào)用的目標(biāo)Activity已經(jīng)位于調(diào)用者的Task的棧頂谜洽,則不創(chuàng)建新實(shí)例,而是使用當(dāng)前的這個(gè)Activity實(shí)例吴叶,并調(diào)用這個(gè)實(shí)例的onNewIntent方法阐虚。

在singleTop這種模式下,我們需要處理應(yīng)用這個(gè)模式的Activity的onCreate和onNewIntent兩個(gè)方法蚌卤,確保邏輯正常实束。

  TaskRecord{537925a8 #42 A com.zlq.lmt U 0}
      Run #4: ActivityRecord{537e3114 com.zlq.lmt/.SingleTopActivity}
      Run #3: ActivityRecord{537dfe7c com.zlq.lmt/.StandardActivity}
      Run #2: ActivityRecord{53770808 com.zlq.lmt/.SingleTopActivity}
      Run #1: ActivityRecord{53760908 com.zlq.lmt/.MainActivity}

棧頂無法像Standard模式一樣,同事存在兩個(gè)逊彭,但是整個(gè)Task列表中間隔存在多個(gè)是可以的咸灿。

SingleTask

棧內(nèi)復(fù)用模式.使用singleTask啟動(dòng)模式的Activity在一個(gè)應(yīng)用Task中只會(huì)存在一個(gè)實(shí)例。如果這個(gè)實(shí)例已經(jīng)存在侮叮,intent就會(huì)通過onNewIntent傳遞到這個(gè)Activity避矢,即多次調(diào)用不會(huì)創(chuàng)建新實(shí)例。否則新的Activity實(shí)例被創(chuàng)建囊榜。
情況包含以下幾種:

  • 同一應(yīng)用內(nèi)
    1. 任務(wù)棧不存在, 初次啟動(dòng)SingleTask實(shí)例, 會(huì)創(chuàng)建任務(wù)棧和實(shí)例.
      Google在singleTask的文檔有這樣一段描述:

The system creates a new task and instantiates the activity at the root of the new task.

意思為 系統(tǒng)會(huì)創(chuàng)建一個(gè)新的Task审胸,并創(chuàng)建Activity實(shí)例放入這個(gè)新的Task的底部。然而實(shí)際并非如此卸勺,在我的例子中砂沛,singleTask Activity并創(chuàng)建并放入了調(diào)用者所在的Task,而不是放入新的Task:
TaskRecord{5378ff88 #44 A com.zlq.lmt U 0}
      Run #3: ActivityRecord{537e2ff0 com.zlq.lmt/.SingleTaskActivity}
      Run #2: ActivityRecord{537de2ec com.zlq.lmt/.StandardActivity}
      Run #1: ActivityRecord{53788be0 com.zlq.lmt/.MainActivity}
怎樣才能符合文檔中所描述的情況呢曙求?那就是 `taskAffinity`屬性和singleTask啟動(dòng)模式配合使用.

```xml
    <activity
        android:name=".SingleTaskWithTaskAffinityActivity"
        android:label="SingleTaskWithTaskAffinityActivity"
        android:launchMode="singleTask"
        android:taskAffinity="com.zlq.new">
    </activity>
    
```

此時(shí)再執(zhí)行同樣的操作碍庵,棧內(nèi)的情況:

TaskRecord{53778428 #45 A com.zlq.new U 0}
      Run #3: ActivityRecord{537db410 com.zlq.lmt/.SingleTaskWithTaskAffinityActivity}
TaskRecord{5378ff88 #44 A com.zlq.lmt U 0}
      Run #2: ActivityRecord{53760908 com.zlq.lmt/.StandardActivity}
      Run #1: ActivityRecord{53788be0 com.zlq.lmt/.MainActivity}
其實(shí),**把啟動(dòng)模式設(shè)置為singleTask悟狱,framework在啟動(dòng)該activity時(shí)只會(huì)把它標(biāo)示為可在一個(gè)新任務(wù)中啟動(dòng)怎抛,至于是否在一個(gè)新任務(wù)中啟動(dòng),還要受其他條件的限制芽淡。**使用`taskAffinity`屬性會(huì)指定新的Activity所屬棧马绝,可與SingleTask配合使用, 對Standard模式無效.新任務(wù)棧是com.zlq.new.
  1. 任務(wù)棧存在, 初次啟動(dòng)SingleTask實(shí)例, Task棧中不存在singleTask Activity的實(shí)例。那么就需要?jiǎng)?chuàng)建這個(gè)Activity的實(shí)例挣菲,并且將這個(gè)實(shí)例放入和調(diào)用者相同的Task中并位于棧頂富稻。與Standard模式相同.
  2. 任務(wù)棧相同,如果singleTask Activity實(shí)例已然存在,再次啟動(dòng)SingleTask實(shí)例, 那么在Activity回退棧中掷邦,所有位于該Activity上面的Activity實(shí)例都將被銷毀掉(銷毀過程會(huì)調(diào)用Activity生命周期回調(diào)),這樣使得singleTask Activity實(shí)例位于棧頂(具有clearTop的效果)椭赋。與此同時(shí)抚岗,Intent會(huì)通過onNewIntent傳遞到這個(gè)SingleTask Activity實(shí)例。 并清除其上面實(shí)例, 具有clearTop的效果.最終哪怔,singleTask Activity實(shí)例會(huì)位于棧頂宣蔚。
  3. 任務(wù)棧不同, 再次啟動(dòng)SingleTask實(shí)例, 會(huì)導(dǎo)致任務(wù)棧切換, 后臺(tái)置于前臺(tái).
  • 跨應(yīng)用之間:
    1. 任務(wù)棧不存在, 初次啟動(dòng)SingleTask實(shí)例, 會(huì)創(chuàng)建一個(gè)新的任務(wù)棧,然后創(chuàng)建SingleTask Activity的實(shí)例认境,將其放入新的Task中胚委。Task變化如下。
TaskRecord{5bf28 #16 A=com.zlq.bbb U=0 sz=1}
        Run #0: ActivityRecord{f4a1b15 u0 com.zlq.bbb/.MainActivityB t16}

變?yōu)椋?/p>

TaskRecord{5c70a93 #17 A=com.zlq.lmt U=0 sz=1}
        Run #1: ActivityRecord{4cd8b0f u0 com.zlq.lmt/.SingleTaskActivity t17}
TaskRecord{5bf28 #16 A=com.zlq.bbb U=0 sz=1}
        Run #0: ActivityRecord{f4a1b15 u0 com.zlq.bbb/.MainActivityB t16}

最近任務(wù)變化:


此處輸入圖片的描述
此處輸入圖片的描述

變?yōu)椋?/p>

此處輸入圖片的描述
此處輸入圖片的描述
  1. 任務(wù)棧存在, 初次啟動(dòng)SingleTask實(shí)例, Task棧中不存在singleTask Activity的實(shí)例叉信。
    如果singleTask Activity所在的應(yīng)用進(jìn)程存在亩冬,但是singleTask Activity實(shí)例不存在,那么從別的應(yīng)用啟動(dòng)這個(gè)Activity硼身,新的Activity實(shí)例會(huì)被創(chuàng)建硅急,并放入到所屬進(jìn)程所在的Task中,并位于棧頂位置佳遂。
Running activities (most recent first):
TaskRecord{5bf28 #16 A=com.zlq.bbb U=0 sz=1}
        Run #1: ActivityRecord{f4a1b15 u0 com.zlq.bbb/.MainActivityB t16}
TaskRecord{65dfdf0 #18 A=com.zlq.lmt U=0 sz=1}
        Run #0: ActivityRecord{f0eba63 u0 com.zlq.lmt/.MainActivity t18}

↓變?yōu)椤?/p>

Running activities (most recent first):
    TaskRecord{65dfdf0 #18 A=com.zlq.lmt U=0 sz=2}
        Run #2: ActivityRecord{73d091c u0 com.zlq.lmt/.SingleTaskActivity t18}
    TaskRecord{5bf28 #16 A=com.zlq.bbb U=0 sz=1}
        Run #1: ActivityRecord{f4a1b15 u0 com.zlq.bbb/.MainActivityB t16}
    TaskRecord{65dfdf0 #18 A=com.zlq.lmt U=0 sz=2}
        Run #0: ActivityRecord{f0eba63 u0 com.zlq.lmt/.MainActivity t18}
  1. 如果singleTask Activity實(shí)例存在营袜,從其他程序被啟動(dòng),那么這個(gè)Activity所在的Task會(huì)被移到頂部丑罪,并且在這個(gè)Task中荚板,位于singleTask Activity實(shí)例之上的所有Activity將會(huì)被正常銷毀掉。如果我們按返回鍵巍糯,那么我們首先會(huì)回退到這個(gè)Task中的其他Activity啸驯,直到當(dāng)前Task的Activity回退棧為空時(shí),才會(huì)返回到調(diào)用者的Task祟峦。
Running activities (most recent first):
      TaskRecord{5bf28 #16 A=com.zlq.bbb U=0 sz=1}
        Run #4: ActivityRecord{f4a1b15 u0 com.zlq.bbb/.MainActivityB t16}
      TaskRecord{65dfdf0 #18 A=com.zlq.lmt U=0 sz=4}
        Run #3: ActivityRecord{fa7aae9 u0 com.zlq.lmt/.StandardActivity t18}
        Run #2: ActivityRecord{dfd9a3b u0 com.zlq.lmt/.StandardActivity t18}
        Run #1: ActivityRecord{660ce3c u0 com.zlq.lmt/.SingleTaskActivity t18}
        Run #0: ActivityRecord{f0eba63 u0 com.zlq.lmt/.MainActivity t18}

↓變?yōu)椤?/p>

Running activities (most recent first):
      TaskRecord{65dfdf0 #18 A=com.zlq.lmt U=0 sz=2}
        Run #2: ActivityRecord{660ce3c u0 com.zlq.lmt/.SingleTaskActivity t18}
      TaskRecord{5bf28 #16 A=com.zlq.bbb U=0 sz=1}
        Run #1: ActivityRecord{f4a1b15 u0 com.zlq.bbb/.MainActivityB t16}
      TaskRecord{65dfdf0 #18 A=com.zlq.lmt U=0 sz=2}
        Run #0: ActivityRecord{f0eba63 u0 com.zlq.lmt/.MainActivity t18}

可以看到罚斗,TASK ID為#18 的任務(wù)棧已經(jīng)從原來的4個(gè)變?yōu)樽罱K的1+1個(gè)。

  • 使用場景:
    該模式的使用場景多類似于郵件客戶端的收件箱或者社交應(yīng)用的時(shí)間線Activity宅楞。上述兩種場景需要對應(yīng)的Activity只保持一個(gè)實(shí)例即可针姿,但是也要謹(jǐn)慎使用這種模式,因?yàn)樗梢栽谟脩粑锤兄那闆r下銷毀掉其他Activity厌衙。

SingleInstance

單實(shí)例模式啟動(dòng)時(shí), 系統(tǒng)會(huì)為其創(chuàng)造一個(gè)單獨(dú)的任務(wù)棧, 以后每次使用, 都會(huì)使用這個(gè)單例, 直到其被銷毀, 屬于真正的單例模式.singleTask差不多距淫,唯一不同的就是存放singleInstance Activity實(shí)例的Task只能存放一個(gè)該模式的Activity實(shí)例,不能有任何其他的Activity婶希。
雖然是兩個(gè)task榕暇,但是在系統(tǒng)的任務(wù)管理器中,卻始終顯示一個(gè),即位于頂部的Task中彤枢。

相關(guān)知識(shí)點(diǎn)

查看當(dāng)前任務(wù)棧:

adb shell dumpsys activity | sed -n -e '/Stack #/p' -e '/Running activities/,/Run #0/p'

輸出的結(jié)果如:

Running activities (most recent first):
      TaskRecord{65dfdf0 #18 A=com.zlq.lmt U=0 sz=2}
        Run #2: ActivityRecord{660ce3c u0 com.zlq.lmt/.SingleTaskActivity t18}
      TaskRecord{5bf28 #16 A=com.zlq.bbb U=0 sz=1}
        Run #1: ActivityRecord{f4a1b15 u0 com.zlq.bbb/.MainActivityB t16}
      TaskRecord{65dfdf0 #18 A=com.zlq.lmt U=0 sz=2}
        Run #0: ActivityRecord{f0eba63 u0 com.zlq.lmt/.MainActivity t18}

TaskRecord{65dfdf0 #18 A=com.zlq.lmt U=0 sz=2}為例
以TaskRecord開頭的(如)為一組 TaskRecord記錄狰晚,#18為Task的ID,A=包名缴啡,sz為該Task的Activity數(shù)量壁晒。
以Run #開頭的為一個(gè)ActivityRecord記錄。其中也包含了包名业栅、類名秒咐、TASK ID等信息。

其中以Task ID為一個(gè)任務(wù)棧的唯一標(biāo)識(shí)碘裕,ID相同的TaskRecord屬于同一個(gè)任務(wù)棧(可以理解為同一應(yīng)用)携取。

對startActivityForResult的影響:

startActivityForResult 不同于 startActivity, 在使用 startActivityForResult 時(shí)不管LaunchMode設(shè)置為哪種模式,都會(huì)在調(diào)用者Task棧中新建實(shí)例以正確地返回?cái)?shù)據(jù)娘汞。在棧中的展現(xiàn)形式均與Standard相同(可生成多份連續(xù)的實(shí)例)歹茶。

  • SingleTop,當(dāng)其使用startActivityForResult時(shí)表現(xiàn)和Standard啟動(dòng)模式時(shí)完全相同
  • SingleTask夕玩,當(dāng)不定義 taskAffinity 屬性時(shí)使用startActivityForResult和Standard啟動(dòng)模式時(shí)表現(xiàn)完全相同你弦。當(dāng)定義了taskAffinity 屬性后,變現(xiàn)將和下面第3條表現(xiàn)一致燎孟。
  • SingleInstance禽作,無法通過startActivity創(chuàng)建自己(無論當(dāng)前所屬哪個(gè)棧)。startActivityForResult 隨意在當(dāng)前棧(傳入者所在棧)新建實(shí)例揩页。
 Running activities (most recent first):
      TaskRecord{ef9f20b #33 A=com.zlq.lmt U=0 sz=4}
        Run #3: ActivityRecord{34f60b1 u0 com.zlq.lmt/.SingleTaskActivity t33} *
        Run #2: ActivityRecord{914547d u0 com.zlq.lmt/.SingleTaskActivity t33} *
        Run #1: ActivityRecord{a1f3e09 u0 com.zlq.lmt/.SingleTaskActivity t33}
        Run #0: ActivityRecord{f7db1c u0 com.zlq.lmt/.MainActivity t33}

上面代碼片段中旷偿,加了*標(biāo)的表示使用startActivity無法建立,是 使用startActivityForResult 建立的Activity爆侣。
由此可知, 因?yàn)閟tartActivityForResult需要返回值, 會(huì)保留實(shí)例, 部分覆蓋單例效果.

注意: 4.x版本通過startActivityForResult啟動(dòng)singleTask, 無法正常獲取返回值, 參考.
5.x以上版本修復(fù)此問題, 考慮兼容性, 不推薦使用startActivityForResult和singleTask.

Demo源碼

以上均為參考資料和自己實(shí)踐驗(yàn)證所得結(jié)果萍程。有描述不清楚的地方,大家可去下載我的代碼自行驗(yàn)證各種情況:GitHub

參考資料鏈接

深入講解Android中Activity launchMode
分析 Activity 的啟動(dòng)模式
Android中Activity四種啟動(dòng)模式和taskAffinity屬性詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末兔仰,一起剝皮案震驚了整個(gè)濱河市茫负,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乎赴,老刑警劉巖忍法,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異榕吼,居然都是意外死亡饿序,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門羹蚣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來原探,“玉大人,你說我怎么就攤上這事⊙氏遥” “怎么了告匠?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長离唬。 經(jīng)常有香客問我后专,道長,這世上最難降的妖魔是什么输莺? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任戚哎,我火速辦了婚禮,結(jié)果婚禮上嫂用,老公的妹妹穿的比我還像新娘型凳。我一直安慰自己,他們只是感情好嘱函,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布甘畅。 她就那樣靜靜地躺著,像睡著了一般往弓。 火紅的嫁衣襯著肌膚如雪疏唾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天函似,我揣著相機(jī)與錄音槐脏,去河邊找鬼。 笑死撇寞,一個(gè)胖子當(dāng)著我的面吹牛顿天,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔑担,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼牌废,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了啤握?” 一聲冷哼從身側(cè)響起鸟缕,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恨统,沒想到半個(gè)月后叁扫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡畜埋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年莫绣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悠鞍。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡对室,死狀恐怖模燥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情掩宜,我是刑警寧澤蔫骂,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站牺汤,受9級特大地震影響辽旋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜檐迟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一补胚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧追迟,春花似錦溶其、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至廓块,卻和暖如春厢绝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剿骨。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工代芜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留埠褪,地道東北人浓利。 一個(gè)月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像钞速,于是被迫代替她去往敵國和親贷掖。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

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