Activity 啟動(dòng)模式全解析
一、任務(wù)與返回棧 (Tasks and Back Stack)
任務(wù)的定義:執(zhí)行特定作業(yè)時(shí)與用戶交互的一系列 Activity。這些 Activity 按照各自的打開(kāi)順序排列在堆棧(即返回棧)中,堆棧頂部 Activity 即為可見(jiàn)的界面。堆棧中的 Activity 永遠(yuǎn)不會(huì) 重新排列,僅推入(push)和彈出(pop)堆棧:由當(dāng)前 Activity 啟動(dòng)時(shí)推入堆棧;用戶使用 Back 按鈕退出時(shí)彈出堆棧。當(dāng)所有 Activity 均從堆棧中移除后,任務(wù)即不復(fù)存在。
舉個(gè)例子,Contacts 應(yīng)用的 PeopleActivity 可以啟動(dòng) QuickContactActivity 來(lái)查看聯(lián)系人信息,而 QuickContactActivity 可以通過(guò) Intent 啟動(dòng) Email 應(yīng)用的編寫(xiě)郵件的 Activity。雖然 Activity 來(lái)自不同的應(yīng)用,但是它們都被保留在相同的任務(wù)中以保持無(wú)縫的用戶體驗(yàn):用戶按 Back 鍵時(shí),會(huì)逐個(gè)回退到上一個(gè) Activity,仿佛這些 Activity 是屬于同一個(gè)應(yīng)用的。
任務(wù)作為一個(gè)整體而存在,簡(jiǎn)單來(lái)說(shuō)就是在某個(gè) Activity 按 Home 鍵之后,該 Activity 所在的任務(wù)就被移到后臺(tái),但任務(wù)的返回棧不變。切換回這個(gè) Activity 后,按 Back 鍵可以發(fā)現(xiàn)回退到了堆棧的上一個(gè) Activity?;谌蝿?wù)與其返回棧的關(guān)系,我們使用任務(wù)棧來(lái)表達(dá)其含義。
Activity 和任務(wù)的默認(rèn)行為總結(jié)如下:
當(dāng) Activity A 啟動(dòng) Activity B 時(shí),
- Activity A 將會(huì)停止,但系統(tǒng)會(huì)保留其狀態(tài)(例如,滾動(dòng)位置和已輸入表單中的文本)。
- 創(chuàng)建 Activity B 的實(shí)例并向其傳送 Intent,其將被推入 Activity A 的任務(wù)棧中。
處于 Activity B 時(shí)按 Back 按鈕
- 當(dāng)前 Activity B 會(huì)從堆棧彈出并被銷(xiāo)毀。銷(xiāo)毀 Activity 時(shí),系統(tǒng)不會(huì)保留該 Activity 的狀態(tài)。
- 堆棧中的前一個(gè) Activity A 恢復(fù)其狀態(tài),繼續(xù)執(zhí)行。
用戶通過(guò)按 Home 按鈕離開(kāi)任務(wù)時(shí),
- 當(dāng)前 Activity 將停止且其任務(wù)會(huì)進(jìn)入后臺(tái)。
- 系統(tǒng)將保留任務(wù)中每個(gè) Activity 的狀態(tài)。
選擇開(kāi)始任務(wù)的啟動(dòng)器圖標(biāo)來(lái)恢復(fù)任務(wù),
- 任務(wù)將出現(xiàn)在前臺(tái)并恢復(fù)執(zhí)行堆棧頂部的 Activity。
- 如果用戶長(zhǎng)時(shí)間離開(kāi)任務(wù),則系統(tǒng)會(huì)清除任務(wù)棧中除根 Activity 之外的所有 Activity。當(dāng)用戶再次返回到任務(wù)時(shí),僅恢復(fù)根 Activity。
二、管理任務(wù)
上面提到的默認(rèn)行為適用于大多數(shù)的 Activity,不需要額外的設(shè)置即可滿足應(yīng)用的需要。但有時(shí)候需要打破這種默認(rèn)的行為,比如,打開(kāi)應(yīng)用的第一個(gè) Activity A,然后用戶注冊(cè)經(jīng)過(guò)了一個(gè)或多個(gè) Activity,注冊(cè)完成后回到第一個(gè) Activity A,如果按照默認(rèn)的行為,堆棧中將會(huì)實(shí)例化兩個(gè) Activity A,而且這兩個(gè)之間還包含了注冊(cè)用的 Activity,這樣子在用戶 Back 鍵想退出應(yīng)用的時(shí)候,就會(huì)跳轉(zhuǎn)到不想要跳轉(zhuǎn)到的注冊(cè)用的 Activity,這就要求回到 Activity A 時(shí)清除注冊(cè)用的 Activity?;蛘撸_(kāi)發(fā)者希望用戶不論在哪個(gè) Activity 切換到后臺(tái)時(shí),再開(kāi)啟應(yīng)用時(shí)要從應(yīng)用的第一個(gè) Activity 開(kāi)始。
這些不符合默認(rèn)行為的操作可以通過(guò)指定 Manifest 文件中 <activity> 元素中的屬性和傳遞給 startActivity() 的 Intent 中的標(biāo)志來(lái)完成設(shè)置。
注意: 應(yīng)用大多數(shù)情況下都不必改變 Activity 和任務(wù)的默認(rèn)行為;如果確定必須修改默認(rèn)行為,請(qǐng)測(cè)試使用 Back 按鈕從其他 Activity 或從 Recent 界面回到該 Activity 時(shí)的行為,確認(rèn)應(yīng)用的行為是否有可能與用戶的預(yù)期行為沖突。
在清單文件中聲明 Activity 時(shí),可以指定 Activity 在啟動(dòng)時(shí)應(yīng)該如何與任務(wù)關(guān)聯(lián)??梢允褂玫?<activity> 屬性有:
- launchMode
- taskAffinity
- allowTaskReparenting
- clearTaskOnLaunch
- alwaysRetainTaskState
- finishOnTaskLaunch
調(diào)用 startActivity() 時(shí),可以在 Intent 中加入一個(gè)標(biāo)志,用于聲明新 Activity 如何(或是否)與當(dāng)前任務(wù)關(guān)聯(lián)。可以使用的 Intent 標(biāo)志主要有:
- FLAG_ACTIVITY_NEW_TASK
- FLAG_ACTIVITY_CLEAR_TOP
- FLAG_ACTIVITY_SINGLE_TOP
如果 Activity A 啟動(dòng) Activity B,則 Activity B 可以在其清單文件中定義它應(yīng)該如何與當(dāng)前任務(wù)關(guān)聯(lián),并且 Activity A 還可以請(qǐng)求 Activity B 應(yīng)該如何與當(dāng)前任務(wù)關(guān)聯(lián)。如果這兩個(gè) Activity 均定義 Activity B 應(yīng)該如何與任務(wù)關(guān)聯(lián),則 Activity A 的請(qǐng)求(如 Intent 中所定義)優(yōu)先級(jí)要高于 Activity B 的請(qǐng)求(如其清單文件中所定義)。
我們將屬性分為兩組:
- 改變?nèi)蝿?wù)啟動(dòng) Activity 時(shí)的默認(rèn)行為
- launchMode
- taskAffinity
- allowTaskReparenting
- 改變?nèi)蝿?wù)恢復(fù) Activity 時(shí)的默認(rèn)行為
- clearTaskOnLaunch
- alwaysRetainTaskState
- finishOnTaskLaunch
1. 改變?nèi)蝿?wù)啟動(dòng) Activity 時(shí)的默認(rèn)行為
1.1. launchMode 和 taskAffinity
launchMode 包括了四種屬性值:standard (默認(rèn)模式)、singleTop、singleTask、singleInstance。相應(yīng)的,使用 FLAG_ACTIVITY_SINGLE_TOP 標(biāo)志產(chǎn)生與 singleTop 相同的行為,而FLAG_ACTIVITY_NEW_TASK 與 FLAG_ACTIVITY_CLEAR_TOP 一般一起使用,產(chǎn)生與 singleTask 相同的行為,一般不單獨(dú)使用,因?yàn)閱为?dú)使用常常導(dǎo)致奇怪的效果。
taskAffinity 指示 Activity 優(yōu)先屬于哪個(gè)任務(wù)。默認(rèn)情況下,同一應(yīng)用中的所有 Activity 默認(rèn)使用軟件包名稱彼此關(guān)聯(lián)。在不同應(yīng)用中定義的 Activity 可以共享關(guān)聯(lián),或者可為在同一應(yīng)用中定義的 Activity 分配不同的任務(wù)關(guān)聯(lián)。taskAffinity 僅在兩種情況下起作用:一是 Activity 的 launchMode 為 singleTask(即以 FLAG_ACTIVITY_NEW_TASK 的 Intent 啟動(dòng)的應(yīng)用);一是 Activity 將其 allowTaskReparenting 屬性設(shè)置為 "true"。
以下我們將分別解釋 launchMode 的行為及對(duì)其進(jìn)行測(cè)試分析。測(cè)試所用的應(yīng)用代碼在這里。
1.1.1. standard (默認(rèn)模式)
系統(tǒng)在啟動(dòng) Activity 的任務(wù)中創(chuàng)建被啟用的 Activity 的新實(shí)例并向其傳送 Intent。Activity 可以多次實(shí)例化,而每個(gè)實(shí)例可屬于不同的任務(wù)或者一個(gè)任務(wù)可以擁有多個(gè)實(shí)例。
測(cè)試 1:
MainActivity --> StandardActivity --> StandardActivity --> StandardActivity
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1189 HashCode:241879363
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
StandardActivity TaskId: 1189 HashCode:64163597
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
StandardActivity TaskId: 1189 HashCode:60617326
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
StandardActivity TaskId: 1189 HashCode:227576965
taskAffinity:com.mupceet.activitytaskdemo
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| Activity 由 A 啟動(dòng)則它與 A 存在于同一任務(wù)棧中 | TaskId 相同 |
| 每次啟動(dòng) Activity 都會(huì)創(chuàng)建一個(gè)新的實(shí)例 | StandardActivity 創(chuàng)建時(shí)走 onCreate 方法,HashCode 不相同 |
1.1.2. singleTop
如果當(dāng)前任務(wù)棧的棧頂為 Activity 的一個(gè)實(shí)例,則系統(tǒng)會(huì)通過(guò)調(diào)用該實(shí)例的 onNewIntent() 方法向其傳送 Intent,而不是創(chuàng)建 Activity 的新實(shí)例。但如果棧頂?shù)?Activity 并不是 Activity 的現(xiàn)有實(shí)例,Activity 的表現(xiàn)與 standard 模式相同。
注: 為某個(gè) Activity 創(chuàng)建新實(shí)例時(shí),用戶可以按 Back 按鈕返回到前一個(gè) Activity。 但是,當(dāng) Activity 的現(xiàn)有實(shí)例處理新 Intent 時(shí),則在新 Intent 到達(dá) onNewIntent() 之前,用戶無(wú)法按 Back 按鈕返回到 Activity 的狀態(tài)。
測(cè)試 2:SingleTopActivity 啟動(dòng)后處于棧頂
MainActivity --> SingleTopActivity --> SingleTopActivity --> SingleTopActivity
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1190 HashCode:242719467
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleTopActivity TaskId: 1190 HashCode:122301260
taskAffinity:com.mupceet.activitytaskdemo
************* onNewIntent *************
SingleTopActivity TaskId: 1190 HashCode:122301260
taskAffinity:com.mupceet.activitytaskdemo
************* onNewIntent *************
SingleTopActivity TaskId: 1190 HashCode:122301260
taskAffinity:com.mupceet.activitytaskdemo
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| Activity 由 A 啟動(dòng)則它與 A 存在于同一任務(wù)棧中 | TaskId 相同 |
| 第一次啟動(dòng) Activity 會(huì)創(chuàng)建一個(gè)實(shí)例 | 第一次啟動(dòng) SingleTopActivity 時(shí)運(yùn)行 onCreate 方法 |
| 多次啟動(dòng) Activity (處于棧頂) 只會(huì)回調(diào) onNewIntent 方法 | 啟動(dòng) SingleTopActivity 后,再多次啟動(dòng) SingleTopActivity,Intent 由 onNewIntent 處理,且 HashCode 相同 |
測(cè)試 3:SingleTopActivity 啟動(dòng)后不處于棧頂
MainActivity --> SingleTopActivity --> OtherTopActivity --> SingleTopActivity
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1191 HashCode:145258514
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleTopActivity TaskId: 1191 HashCode:9399791
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
OtherTopActivity TaskId: 1191 HashCode:209949367
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleTopActivity TaskId: 1191 HashCode:48271010
taskAffinity:com.mupceet.activitytaskdemo
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| 再次啟動(dòng) Activity (不處于棧頂) 會(huì)創(chuàng)建一個(gè)新實(shí)例 | 第二次啟動(dòng) SingleTopActivity,運(yùn)行 onCreate 方法,且 HashCode 不相同 |
1.1.3. singleTask
系統(tǒng)不存在該任務(wù)(taskAffinity 標(biāo)識(shí)的任務(wù)名)則創(chuàng)建新任務(wù)并實(shí)例化 Activity 推入任務(wù)棧底。如果存在任務(wù),但沒(méi)有實(shí)例,將實(shí)例化 Activity 并推入任務(wù)棧,但是,如果該 Activity 的一個(gè)實(shí)例已存在于任務(wù)中,則系統(tǒng)會(huì)通過(guò)調(diào)用現(xiàn)有實(shí)例的 onNewIntent() 方法向其傳送 Intent,并且原來(lái)?xiàng)V刑幱?Activity 之上的被清理出棧。即任務(wù)棧中只能存在 Activity 的一個(gè)實(shí)例。
注: 盡管 Activity 在新 Task 中啟動(dòng),但是用戶按 Back 按鈕仍會(huì)返回到前一個(gè) Activity。
測(cè)試 4:SingleTaskActivity 不指定 taskAffinity
MainActivity --> SingleTaskActivity --> OtherTaskActivity --> SingleTaskActivity
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1192 HashCode:160080556
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleTaskActivity TaskId: 1192 HashCode:125240432
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
OtherTaskActivity TaskId: 1192 HashCode:35483478
taskAffinity:com.mupceet.activitytaskdemo
************* onNewIntent *************
SingleTaskActivity TaskId: 1192 HashCode:125240432
taskAffinity:com.mupceet.activitytaskdemo
Running activities (most recent first):
TaskRecord{216074a #1218 A=com.mupceet.activitytaskdemo U=0 StackId=1 sz=2}
Run #1: ActivityRecord{8ca4bea u0 com.mupceet.activitytaskdemo/.SingleTaskActivity t1218}
Run #0: ActivityRecord{5a6a171 u0 com.mupceet.activitytaskdemo/.MainActivity t1218}
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| Activity 由 A 啟動(dòng)則它與 A 存在于同一任務(wù)棧中 | TaskId 相同 |
| 再次啟動(dòng) Activity 會(huì)回調(diào) onNewIntent 方法 | 再次啟動(dòng) SingleTaskActivity,Intent 由 onNewIntent 處理,且 HashCode 相同 |
| 原來(lái)?xiàng)V刑幱?Activity 之上的被清理出棧 | 再次啟動(dòng) SingleTaskActivity 后,棧中僅有兩個(gè) Activity |
測(cè)試 5:SingleTaskActivity 指定 taskAffinity
MainActivity --> SingleTaskActivityWithAffinity --> StandardActivity
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1200 HashCode:176168109
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleTaskActivityWithAffinity TaskId: 1201 HashCode:95759438
taskAffinity:com.mupceet.task2
************* onCreate *************
StandardActivity TaskId: 1201 HashCode:233514981
taskAffinity:com.mupceet.activitytaskdemo
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| Activity 啟動(dòng)到新的任務(wù)棧中 | MainActivity 與 SingleTaskActivityWithAffinity 的 TaskId 不相同 |
| Activity 啟動(dòng) standard 模式的 Activity 處于同一任務(wù)棧 | 啟動(dòng) StandardActivity,兩者的 TaskId 相同 |
測(cè)試 6:SingleTaskActivity 和 OtherActivity 指定相同 taskAffinity
(TaskDemo) MainActivity --> SingleTaskActivityWithAffinity --> home 返回主頁(yè)
(TaskDemo2) MainActivity --> OtherActivityWithAffinity
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1202 HashCode:8042982
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleTaskActivityWithAffinity TaskId: 1203 HashCode:37289106
taskAffinity:com.mupceet.task2
************* onCreate *************
MainActivity TaskId: 1204 HashCode:241879363
taskAffinity:com.mupceet.activitytaskdemo2
************* onCreate *************
OtherActivityWithActivity TaskId: 1203 HashCode:186496063
taskAffinity:com.mupceet.task2
Running activities (most recent first):
TaskRecord{5d38658 #1203 A=com.mupceet.task2 U=0 StackId=1 sz=2}
Run #3: ActivityRecord{f653f3 u0 com.mupceet.activitytaskdemo2/.OtherActivityWithActivity t1203}
TaskRecord{532c417 #1204 A=com.mupceet.activitytaskdemo2 U=0 StackId=1 sz=1}
Run #2: ActivityRecord{2a6ae8b u0 com.mupceet.activitytaskdemo2/.MainActivity t1204}
TaskRecord{5d38658 #1203 A=com.mupceet.task2 U=0 StackId=1 sz=2}
Run #1: ActivityRecord{6ebc71c u0 com.mupceet.activitytaskdemo/.SingleTaskActivityWithAffinity t1203}
TaskRecord{43259ed #1202 A=com.mupceet.activitytaskdemo U=0 StackId=1 sz=1}
Run #0: ActivityRecord{df97ca7 u0 com.mupceet.activitytaskdemo/.MainActivity t1202}
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| Activity 啟動(dòng)到新的任務(wù)棧中 | MainActivity 與 SingleTaskActivityWithAffinity 的 TaskId 不相同 |
| 具有相同 taskAffinity 的 Activity 啟動(dòng)后將處于同一任務(wù)棧 | SingleTaskActivityWithAffinity 與 OtherActivityWithActivity 的 TaskId 相同 |
注意,這里有個(gè)現(xiàn)象需要注意,即如果存在任務(wù),但沒(méi)有實(shí)例,將實(shí)例化 Activity 并推入任務(wù)棧,這個(gè)任務(wù)棧就在前臺(tái)運(yùn)行,此時(shí)按 Back 鍵得直到此任務(wù)棧清空后才會(huì)回到啟動(dòng)該 Activity 的那個(gè)任務(wù)棧,而不是像平常一次返回就可以返回啟動(dòng) Activity。如果不明白這段話,只要將測(cè)試 6 的步驟改動(dòng)一下為:
(TaskDemo) MainActivity --> SingleTaskActivityWithAffinity --> StandardActivity --> StandardActivity --> home 返回主頁(yè)
(TaskDemo2) MainActivity --> OtherActivityWithAffinity
再點(diǎn)擊幾次 Back 鍵就知道是什么意思
1.1.4. singleInstance
與 "singleTask" 類(lèi)似,但系統(tǒng)不會(huì)將任何其他 Activity 啟動(dòng)到包含該 Activity 實(shí)例的任務(wù)棧中。即該 Activity 始終是其任務(wù)棧唯一僅有的成員;由此 Activity 啟動(dòng)的任何 Activity 均在其他的任務(wù)中打開(kāi)。
測(cè)試 7:
MainActivity--> SingleInstanceActivity--> MainActivity--> SingleInstanceActivity
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1194 HashCode:19028065
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleInstanceActivity TaskId: 1195 HashCode:109601484
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
MainActivity TaskId: 1194 HashCode:202770375
taskAffinity:com.mupceet.activitytaskdemo
************* onNewIntent *************
SingleInstanceActivity TaskId: 1195 HashCode:109601484
taskAffinity:com.mupceet.activitytaskdemo
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| Activity 啟動(dòng)到新的任務(wù)棧中,即使是默認(rèn)的 taskAffinity | MainActivity 與 SingleInstanceActivity 的 TaskId 不相同 |
| 除了第一次啟動(dòng)時(shí)創(chuàng)建實(shí)例,其它多次啟動(dòng)復(fù)用并調(diào)到前臺(tái) | SingleInstanceActivity 的 HashCode 相同,Intent 由 onNewIntent 處理 |
| 啟動(dòng)的 Activity 運(yùn)行在其他任務(wù)棧中 | SingleInstanceActivity 與 MainActivity 的 TaskId 不相同,而且由于 MainActivity 是 standard 模式,啟動(dòng)時(shí)創(chuàng)建了新實(shí)例,棧中有兩個(gè) MainActivity 實(shí)例 |
測(cè)試 8:在測(cè)試 7 基礎(chǔ)上改為調(diào)用 SingleTopActivity
MainActivity--> SingleTopActivity--> SingleInstanceActivity--> SingleTopActivity--> SingleInstanceActivity
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1196 HashCode:141418922
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleTopActivity TaskId: 1196 HashCode:74869513
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleInstanceActivity TaskId: 1197 HashCode:193894545
taskAffinity:com.mupceet.activitytaskdemo
************* onNewIntent *************
SingleTopActivity TaskId: 1196 HashCode:74869513
taskAffinity:com.mupceet.activitytaskdemo
************* onNewIntent *************
SingleInstanceActivity TaskId: 1197 HashCode:193894545
taskAffinity:com.mupceet.activitytaskdemo
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| Activity 啟動(dòng)到新的任務(wù)棧中,即使用默認(rèn)的 taskAffinity | MainActivity 與 SingleInstanceActivity 的 TaskId 不相同 |
| 除了第一次啟動(dòng)時(shí)創(chuàng)建實(shí)例,其它多次啟動(dòng)復(fù)用并調(diào)到前臺(tái) | SingleInstanceActivity 的 HashCode 相同,Intent 由 onNewIntent 處理 |
| 啟動(dòng)的 Activity 運(yùn)行在其他任務(wù)棧中 | 啟動(dòng)的 SingleTopActivity 的 HashCode 相同,因?yàn)?SingleTopActivity 是 singleTop 模式,啟動(dòng)時(shí)未創(chuàng)建新實(shí)例,Intent 由 onNewIntent 處理 |
測(cè)試 9:
MainActivity--> SingleInstanceActivity--> StandardActivity
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1206 HashCode:241879363
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleInstanceActivity TaskId: 1209 HashCode:213193939
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
StandardActivity TaskId: 1206 HashCode:213531793
taskAffinity:com.mupceet.activitytaskdemo
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| Activity 啟動(dòng)到新的任務(wù)棧中,即使用默認(rèn)的 taskAffinity | MainActivity 與 SingleInstanceActivity 的 TaskId 不相同 |
| 啟動(dòng)的 Activity 運(yùn)行在其他任務(wù)棧中 | SingleInstanceActivity 與 StandardActivity 的 TaskId 不相同,但由于 StandardActivity 和 MainActivity 的 taskAffinity 相同,它們存在于同一個(gè)任務(wù)棧中 |
測(cè)試 10:
(TaskDemo) MainActivity --> SingleInstanceActivity --> home 返回主頁(yè)
(TaskDemo2) MainActivity --> SingleInstanceActivity
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1206 HashCode:241879363
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
SingleInstanceActivity TaskId: 1207 HashCode:64163597
taskAffinity:com.mupceet.activitytaskdemo
************* onCreate *************
MainActivity TaskId: 1208 HashCode:241879363
taskAffinity:com.mupceet.activitytaskdemo2
************* onNewIntent *************
SingleInstanceActivity TaskId: 1207 HashCode:64163597
taskAffinity:com.mupceet.activitytaskdemo
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| Activity 在系統(tǒng)中僅會(huì)存在一個(gè)實(shí)例 | 不同應(yīng)用啟動(dòng)的 SingleInstanceActivity 的 TaskId 相同,HashCode 相同 |
1.2. allowTaskReparenting
在這種屬性情況下,Activity 在其關(guān)聯(lián)的任務(wù)轉(zhuǎn)到前臺(tái)時(shí),將從原先被啟動(dòng)時(shí)推入的任務(wù)棧移動(dòng)到與其具有關(guān)聯(lián)的任務(wù)棧中。
測(cè)試 11:TaskDemo2 啟動(dòng) TaskDemo 的 StandardActivity
(TaskDemo2) MainActivity --> ToDemoStandard --> home 返回主頁(yè)
(TaskDemo) MainActivity(打開(kāi)應(yīng)用)
結(jié)果:
************* onCreate *************
MainActivity TaskId: 1220 HashCode:241879363
taskAffinity:com.mupceet.activitytaskdemo2
************* onCreate *************
StandardActivity TaskId: 1220 HashCode:241879363
taskAffinity:com.mupceet.activitytaskdemo
(打開(kāi) Demo 應(yīng)用無(wú)輸出)
打開(kāi) TaskDemo 前:
Running activities (most recent first):
TaskRecord{f0c1e3 #1222 A=com.mupceet.activitytaskdemo2 U=0 StackId=1 sz=2}
Run #1: ActivityRecord{a32ff5f u0 com.mupceet.activitytaskdemo/.StandardActivity t1222}
Run #0: ActivityRecord{371f577 u0 com.mupceet.activitytaskdemo2/.MainActivity t1222}
打開(kāi) TaskDemo 后:
Running activities (most recent first):
TaskRecord{18af934 #1223 A=com.mupceet.activitytaskdemo U=0 StackId=1 sz=2}
Run #1: ActivityRecord{a32ff5f u0 com.mupceet.activitytaskdemo/.StandardActivity t1223}
TaskRecord{f0c1e3 #1222 A=com.mupceet.activitytaskdemo2 U=0 StackId=1 sz=1}
Run #0: ActivityRecord{371f577 u0 com.mupceet.activitytaskdemo2/.MainActivity t1222}
解析:
| 結(jié)論 | 來(lái)源 |
|---|---|
| standard 模式的 Activity 被啟動(dòng)時(shí)將被推入啟動(dòng)的任務(wù)棧中 | Demo2 的 MainActivity 與其啟動(dòng)的 Demo 的 StandardActivity 的 TaskId 相同 |
| allowTaskReparenting 的 Activity 被其關(guān)聯(lián)的任務(wù)啟動(dòng)時(shí)將被轉(zhuǎn)移到關(guān)聯(lián)的任務(wù)棧中 | Demo 啟動(dòng)的 StandardActivity 未重新實(shí)例化,而是在任務(wù)棧中移動(dòng) |
2. 改變?nèi)蝿?wù)恢復(fù) Activity 時(shí)的默認(rèn)行為
如上文默認(rèn)行為所述,如果用戶長(zhǎng)時(shí)間離開(kāi)任務(wù),則系統(tǒng)會(huì)清除任務(wù)棧中除根 Activity 之外的所有 Activity。當(dāng)用戶再次返回到任務(wù)時(shí),僅恢復(fù)根 Activity。系統(tǒng)這樣做的原因是,經(jīng)過(guò)很長(zhǎng)一段時(shí)間后,用戶可能已經(jīng)放棄之前執(zhí)行的操作,返回到任務(wù)是要開(kāi)始執(zhí)行新的操作。要修改恢復(fù) Activity 任務(wù)棧的行為可以使用以下三個(gè)屬性。
2.1. alwaysRetainTaskState
如果在任務(wù)的根 Activity 中將此屬性設(shè)置為 "true",則不會(huì)發(fā)生剛才所述的默認(rèn)行為。即使在很長(zhǎng)一段時(shí)間后,任務(wù)仍將所有 Activity 保留在其堆棧中。
2.2. clearTaskOnLaunch
如果在任務(wù)的根 Activity 中將此屬性設(shè)置為 "true",則每當(dāng)用戶離開(kāi)任務(wù)然后點(diǎn)擊圖標(biāo)返回時(shí),系統(tǒng)都會(huì)將堆棧清除到只剩下根 Activity。即使只離開(kāi)任務(wù)片刻時(shí)間,用戶也始終會(huì)返回到任務(wù)的初始狀態(tài)。
測(cè)試 12:點(diǎn)擊屬于 TaskDemo2 的 StandardActivity 圖標(biāo)
StandardActivity --> StandardActivity --> StandardActivity --> StandardActivity
結(jié)果:
************* onCreate *************
StandardActivity TaskId: 1229 HashCode:241879363
taskAffinity:com.mupceet.activitytaskdemo2
************* onCreate *************
StandardActivity TaskId: 1229 HashCode:235658412
taskAffinity:com.mupceet.activitytaskdemo2
************* onCreate *************
StandardActivity TaskId: 1229 HashCode:188962139
taskAffinity:com.mupceet.activitytaskdemo2
************* onCreate *************
StandardActivity TaskId: 1229 HashCode:34150381
taskAffinity:com.mupceet.activitytaskdemo2
Running activities (most recent first):
TaskRecord{d2b8f13 #1229 A=com.mupceet.activitytaskdemo2 U=0 StackId=1 sz=4}
Run #3: ActivityRecord{e71827f u0 com.mupceet.activitytaskdemo2/.StandardActivity t1229}
Run #2: ActivityRecord{7a51fa1 u0 com.mupceet.activitytaskdemo2/.StandardActivity t1229}
Run #1: ActivityRecord{ef87b33 u0 com.mupceet.activitytaskdemo2/.StandardActivity t1229}
Run #0: ActivityRecord{638598e u0 com.mupceet.activitytaskdemo2/.StandardActivity t1229}
Home 回到主頁(yè)后,再次點(diǎn)擊桌面圖標(biāo)返回
Running activities (most recent first):
TaskRecord{d2b8f13 #1229 A=com.mupceet.activitytaskdemo2 U=0 StackId=1 sz=1}
Run #0: ActivityRecord{638598e u0 com.mupceet.activitytaskdemo2/.StandardActivity t1229}
可以看到任務(wù)棧中僅剩根 Activity 了,點(diǎn)擊一次 Back 即可退出。
2.3. finishOnTaskLaunch
該屬性與 clearTaskOnLaunch 類(lèi)似,但這個(gè)針對(duì)單個(gè) Activity 而不是整個(gè)任務(wù)。在任務(wù)轉(zhuǎn)入后臺(tái)再點(diǎn)擊桌面圖標(biāo)返回時(shí)設(shè)置該屬性為 "true" 的 Activity 將被銷(xiāo)毀。
參考資料: