Android lanchMode -- 不要再簡潔明了了

參考

任務(wù)棧和Activity啟動模式
Android 面試黑洞——當我按下 Home 鍵再切回來少孝,會發(fā)生什么?

前言

之前在網(wǎng)上檢索一些lanchMode的知識继低,發(fā)現(xiàn)一點不言簡意賅,有些把實驗和結(jié)論混合一起的稍走,想法很好袁翁,但閱讀起來其實很混亂,理解起來也麻煩婿脸,沒有整體的框架邏輯去看這些的時候粱胜,好像學(xué)到了啥,其實整體來對比又一團混亂狐树,不體系焙压。

  • 建議

本文就只參考了上面兩個連接,就完全理解lanchMode的整體框架,建議直接看完本篇以后涯曲,再去看這個Android 面試黑洞——當我按下 Home 鍵再切回來答憔,會發(fā)生什么?視頻,看看是否自己理解清楚了掀抹。理解了這個框架虐拓,再去關(guān)于Flag的,就都只是些策略問題了傲武。

以下是一些總結(jié)和問題蓉驹,可以看完以后再回看這些,看看自己是否是真的理解了

  • 默認(standard)和singleTop:多用于App內(nèi)部

  • singleTask:內(nèi)部交互和外部交互都會用上揪利,singleInstance:多用于開放給外部App來共享使用

  • singeTop = standard + 約束

  • singleInstance = singTask + 約束

  • 在最近任務(wù)里看見的Task不一定活著

  • 在最近任務(wù)里看不見的Task不一定死了

  • singleTask流程态兴?

  • singleInstance怎么能做到獨占一個任務(wù)棧

預(yù)熱

在具體開始啟動模式相關(guān)知識的時候,首先需要搞清楚一下兩點

  1. Task任務(wù)棧
  2. taskAffinity

認清任務(wù)棧

首先一個簡單的關(guān)系圖:

ActivityStack.png
  • 任務(wù)棧結(jié)構(gòu)

任務(wù)棧疟位,最直觀的表現(xiàn)就是打開最近任務(wù)的時候瞻润,展示的一個個任務(wù),其實就是一個個task任務(wù)棧

安卓系統(tǒng)管理著不同模式下的多個ActivityStack(比如在home launcher界面需要有一個ActivityStack甜刻,畫中畫模式绍撞,分屏模式等)。

  • 一個ActivityStack可以包含很多個TaskRecord得院。
  • 一個TaskRecord又可以包含很多個ActivityRecord傻铣。
  • 每一個ActivityRecord都會有一個Activity與之對應(yīng),一個Activity可能會有多個ActivityRecord祥绞,因為Activity可能被多次實例化非洲。

一系列相關(guān)的ActivityRecord組成了一個TaskRecord,TaskRecord是存在于ActivityStack中蜕径,ActivityStackSupervisor是用來管理這些ActivityStack的两踏。
launcher也有自己的task,

系統(tǒng)是根據(jù)task進行管理的兜喻,而不是ActivityStack梦染。

  • 前后臺task

task又分為前臺task和后臺task,前臺task(也叫當前task)就是棧頂是和用戶交互的activity的task虹统,后臺task就是非前臺task弓坞。

Activity可以在Task內(nèi)部疊成棧,不同task之間也可以疊成棧车荔,不過只針對前臺task,前臺疊加的多個task渡冻,在進入后臺會立刻被拆開,這也就是造成"singleTask"模式下回退路徑變化的問題。

當前 Activity 啟動另一個 Activity 時忧便,該新 Activity 會被推送到堆棧頂部族吻,成為焦點所在帽借。 前一個 Activity 仍保留在堆棧中,但是處于停止狀態(tài)超歌。Activity 停止時砍艾,系統(tǒng)會保持其用戶界面的當前狀態(tài)。 用戶按"返回"按鈕時巍举,當前 Activity 會從堆棧頂部彈出(Activity 被銷毀)脆荷,而前一個 Activity 恢復(fù)執(zhí)行(恢復(fù)其 UI 的前一狀態(tài))。

如果用戶繼續(xù)按"返回"懊悯,堆棧中的相應(yīng) Activity 就會彈出蜓谋,以顯示前一個 Activity,直到 所有 Activity 均從堆棧中移除后炭分,任務(wù)即不復(fù)存在桃焕,回到桌面,但此時打開最近任務(wù)依然能看到該task的一個“殘影”捧毛。

taskAffinity

清單文件中Application和Activity標簽都可以使用"android:taskAffinity"標記
它代表這個Activity所希望歸屬的Task,也就是分組观堂,在默認情況下,同一個app中的所有Activity擁有共同的Affinity呀忧,即manifest中定義的package师痕。

一個Activity的taskAffinity的優(yōu)先級:activity設(shè)置的 -> Application設(shè)置的 -> packageName

taskAffinity與Task、Activity的關(guān)系

前面說了荐虐,taskAffinity其實就是一個分組標記七兜。

  • Activty有"android:taskAffinity"可以更改標記,默認取自Application的標記福扬, Application默認又取自包名。
  • 對于Task的affinity標記則取決于它的根部Activity惜犀。

多個task可以擁有相同的taskAffinity铛碑,但最近列表只會展示最新展示過的那一個task

taskAffinity在兩種情況下起作用:

知道taskAffinity是標記作用,就很好理解下面的情況了虽界。

  • 當啟動Activity的Intent中帶有FLAG_ACTIVITY_NEW_TASK標志時汽烦。

在默認情況下,目標Activity將與startActivity的調(diào)用者處于同一task中莉御。但如果用戶特別指定了FLAG_ACTIVITY_NEW_TASK撇吞,表明它希望為Activity重新開設(shè)一個Task。這時就有兩種情況:

  1. 假如當前已經(jīng)有一個Task礁叔,它的affinity與新Activity是一樣的牍颈,那么系統(tǒng)會直接用此Task來完成操作,而不是另外創(chuàng)建一個Task琅关;
  2. 否則系統(tǒng)需要創(chuàng)建一個Task煮岁。
  • 當Activity中的allowTaskReparenting屬性設(shè)置為true時。

在這種情況下,Activity具有"動態(tài)轉(zhuǎn)移"的能力画机。舉個前面的"短信"例子冶伞,在默認情況下,該應(yīng)用程序中的所有Activity具有相同的affinity步氏。
當另一個程序啟動了"短信編輯"時响禽,一開始這個Activity和啟動它的Activity處于同樣的Task中。但如果"短信編輯"Activity指定了allowTaskReparenting荚醒,且后期"短信"程序的Task轉(zhuǎn)為前臺金抡,此時"短信編輯"這一Activity會被"挪"到與它更親近的"短信"Task中。

注意:allowTaskReparenting在安卓9.0和10.0可能有問題

啟動模式

在Android中每個界面都是一個Activity腌且,切換界面操作其實是多個不同Activity之間的實例化操作梗肝。在Android中Activity的啟動模式?jīng)Q定了Activity的啟動運行方式。

有兩種方式來聲明指定啟動模式:

  1. 在清單文件中
  2. 在java代碼中

如果 Activity A 啟動 Activity B铺董,則 Activity B 可以在其清單文件中定義它應(yīng)該如何與當前任務(wù)關(guān)聯(lián)(如果可能)巫击,并且 Activity A 還可以請求 Activity B 應(yīng)該如何與當前任務(wù)關(guān)聯(lián)。

如果這兩個方式均定義 Activity B 應(yīng)該如何與任務(wù)關(guān)聯(lián)精续,則 Activity A 的請求(Intent 中所定義)優(yōu)先級要高于 Activity B 的請求(其清單文件中所定義)坝锰。

本篇只講在清單申明的情況

在清單文件中

不管何種方式啟動Activity,被啟動的Activity通常都要位于ActivityStack的棧頂重付。

Activity啟動方式launchMode顷级,在清單文件中配置。

<activity android:name=".MainActivity"

android:launchMode="xxx" />

您可以分配給 launchMode 屬性的啟動模式共有四種:

"standard"(默認模式)

  • 概述:

和任務(wù)棧的taskAffinity沒有直接相關(guān)确垫,啟動一次弓颈,就會在當前任務(wù)棧直接新創(chuàng)建一個實例

也就是說Activity 可以多次實例化,而每個實例均可屬于不同的任務(wù)删掀,并且一個任務(wù)可以擁有多個該activity實例翔冀。

"singleTop"

  • 概述:

和"standard"模式類似,只更當前任務(wù)棧相關(guān)披泪,唯一一點不同是纤子,當要啟動的Activity和當前任務(wù)棧棧頂?shù)腁ctivity一樣時,只調(diào)用該實例的 onNewIntent() 方法向其傳送 Intent款票,而不是創(chuàng)建 Activity 的新實例控硼。

例如,假設(shè)任務(wù)堆棧是 A-B-C-D艾少;D 位于頂部卡乾。收到針對 D 類 Activity 的 Intent,

  • 如果 D 具有默認的 "standard" 啟動模式姆钉,則會啟動該類的新實例说订,且堆棧會變成 A-B-C-D-D抄瓦。
  • 如果 D 的啟動模式是 "singleTop",則 D 的現(xiàn)有實例會通過 onNewIntent() 接收 Intent陶冷,因為它位于堆棧的頂部钙姊;而堆棧仍為 A-B-C-D。
  • 如果收到針對 B 類 Activity 的 Intent埂伦,則會向堆棧添加 B 的新實例煞额,即便其啟動模式為 "singleTop" 也是如此。

"singleTask"

  • 概述:

這種模式和taskAffinity息息相關(guān)沾谜,整體邏輯流程如下:

  • 首先根據(jù)要啟動的Acitivity的taskAffinity找任務(wù)棧膊毁,分三種情況

    1. 已存在對應(yīng)taskAffinity的任務(wù)棧,而且就是當前任務(wù)棧
    2. 已存在對應(yīng)taskAffinity的任務(wù)棧基跑,不是當前任務(wù)棧
    3. 不存在對應(yīng)taskAffinity的任務(wù)棧婚温。則創(chuàng)建新的任務(wù)棧
      注:這里2,3情況媳否,之后任務(wù)棧會疊成棧栅螟,這種方式只適用于前臺task
  • 然后在找到對應(yīng)任務(wù)棧以后,就會在棧里面找是否已經(jīng)有這個Activity了篱竭,分成兩種情況
    a. 已經(jīng)有了力图,則把它彈到棧頂(意思是,它如果不在棧頂掺逼,就把現(xiàn)在棧頂?shù)囊粋€個彈出吃媒,直到它到棧頂為止),并且調(diào)用onNewIntent() 方法向其傳送 Intent吕喘,而不是創(chuàng)建新實例
    b. 沒有的話,則創(chuàng)建新的實例壓棧

下圖這種就是 2a組合的情況:


singleTask Mode.png

對于這個模式赘那,有個回退路變更問題

  • 回退路徑,上面提到了任務(wù)棧的疊加兽泄,因為在切換后臺的時候漓概,疊加任務(wù)棧會被立刻拆分,所以前臺task就只有一個了病梢,回退路徑就會發(fā)生變化。
    這個時候可以考慮屬性allowTaskReparenting梁肿,希望創(chuàng)建新任務(wù)并實例化Activity蜓陌,當然會受到taskAffinity的影響,即如果已經(jīng)有一個和要啟動的Activity的taskAffinity相同的task吩蔑,那么就在這個task中創(chuàng)建實例钮热,相反就是創(chuàng)建一個新任務(wù)。并且會將這個任務(wù)棧壓到當前的任務(wù)棧

"singleInstance"

  • 總結(jié)

這個模式最復(fù)雜烛芬,該模式下隧期,與 "singleTask" 類似飒责,只是條件更嚴苛一點。就是此activity獨占一個任務(wù)棧,而之所以能保證它自己一個獨占一個任務(wù)棧仆潮,是因為多個任務(wù)椇牝龋可以擁有同一個taskAffinity

一旦該模式的Activity的實例存在于某個棧中,任何應(yīng)用再激活該Activity時都會重用該棧中的實例性置,其效果相當于多個應(yīng)用程序共享一個應(yīng)用拾并,不管誰激活該Activity都會進入同一個應(yīng)用中。

singleTask/singleInstance的特別說明

從ActivityStack源碼可以看出鹏浅,singleTask/singleInstance模式會clearTop的效果嗅义,

} else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
        || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
        || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {

從ActivityStack源碼可以看出,singleTask/singleInstance模式會自動添加FLAG_ACTIVITY_NEW_TASK

} else if (mLaunchSingleInstance || mLaunchSingleTask) {
    // The activity being started is a single instance...  it always
    // gets launched into its own task.
    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}

總結(jié)

這里面最好理解的就是standard和singleTop兩個模式了隐砸,而singleTask和singleInstance兩個模式必須先要理解 Task和takeInfinity這兩個概念之碗,然后搞清楚singleTask流程就行,singleInstance就只是加了一個獨占task的條件季希。

整體結(jié)構(gòu)就這些褪那,看完這個,再去看b站 拋物線的視頻胖眷,相信會很容易理解了武通,結(jié)構(gòu)也更加清晰了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市珊搀,隨后出現(xiàn)的幾起案子冶忱,更是在濱河造成了極大的恐慌,老刑警劉巖境析,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件囚枪,死亡現(xiàn)場離奇詭異,居然都是意外死亡劳淆,警方通過查閱死者的電腦和手機链沼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沛鸵,“玉大人括勺,你說我怎么就攤上這事∏” “怎么了疾捍?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長栏妖。 經(jīng)常有香客問我乱豆,道長,這世上最難降的妖魔是什么吊趾? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任宛裕,我火速辦了婚禮瑟啃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘揩尸。我一直安慰自己蛹屿,他們只是感情好,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布疲酌。 她就那樣靜靜地躺著蜡峰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪朗恳。 梳的紋絲不亂的頭發(fā)上湿颅,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音粥诫,去河邊找鬼油航。 笑死,一個胖子當著我的面吹牛怀浆,可吹牛的內(nèi)容都是我干的谊囚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼执赡,長吁一口氣:“原來是場噩夢啊……” “哼镰踏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起沙合,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤奠伪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后首懈,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绊率,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年究履,在試婚紗的時候發(fā)現(xiàn)自己被綠了滤否。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡最仑,死狀恐怖藐俺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情泥彤,我是刑警寧澤紊搪,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站全景,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏牵囤。R本人自食惡果不足惜爸黄,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一滞伟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧炕贵,春花似錦梆奈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鳖轰,卻和暖如春清酥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蕴侣。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工焰轻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人昆雀。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓辱志,卻偏偏與公主長得像,于是被迫代替她去往敵國和親狞膘。 傳聞我的和親對象是個殘疾皇子揩懒,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

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

  • 最近在重新整理Activity的啟動模式,順便也扒了扒任務(wù)棧Task挽封,接著又去了解了下Android的概覽屏幕已球,把...
    Find_A_Way閱讀 508評論 0 1
  • 久違的晴天,家長會场仲。 家長大會開好到教室時和悦,離放學(xué)已經(jīng)沒多少時間了。班主任說已經(jīng)安排了三個家長分享經(jīng)驗渠缕。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,523評論 16 22
  • 今天感恩節(jié)哎鸽素,感謝一直在我身邊的親朋好友。感恩相遇亦鳞!感恩不離不棄馍忽。 中午開了第一次的黨會,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,564評論 0 11
  • 可愛進取燕差,孤獨成精遭笋。努力飛翔,天堂翱翔徒探。戰(zhàn)爭美好瓦呼,孤獨進取。膽大飛翔测暗,成就輝煌央串。努力進取磨澡,遙望,和諧家園质和∥壬悖可愛游走...
    趙原野閱讀 2,727評論 1 1
  • 在妖界我有個名頭叫胡百曉,無論是何事饲宿,只要找到胡百曉即可有解決的辦法厦酬。因為是只狐貍大家以訛傳訛叫我“傾城百曉”,...
    貓九0110閱讀 3,261評論 7 3