任務和回退棧
一個應用通常有多個Activity。每個Activity圍繞着用戶要執行的具體行爲被設計,其可以啓動其他的Activity。例如,郵件應用有一個Activity用來展示新消息列表。當用戶點擊一個消息項,打開一個新Activity來查看該條消息詳情。
一個Activity也能啓動一個設備上的其他應用的Activity。例如,如果你的應用想要發一封郵件,則你可以定義一個執行”發送”行爲且包含需要數據(比如郵件地址和消息體)的Intent。其他應用程序聲明瞭處理這種的類型Intent的Activity將被打開。上面的情況,定義的Intent是要發送郵件,所以郵件應用的“撰寫”Activity啓動(如果有多個Activity支持這一相同的Intent,則系統會讓用戶選擇使用哪一個)。當郵件被髮送,你的Activity將恢復,這看起來好像郵件Activity是你的應用的一部分。儘管activity來自不同的應用,Android通過保持所有的Activity在一個相同的任務棧來維持無縫的用戶體驗。
任務是當執行一項具體工作時用戶與之交互的Activity的集合。這些Activity按打開的順序被放置在一個棧裏(回退棧)。
設備的主屏幕是大部分任務啓動的地方。當用戶在桌面上點擊一個應用程序圖標時,這個應用程序的任務被調到前臺。如果這個應用程序沒有任務存在,則會創建一個新的任務,並且該應用的“主”Activity將被打開作爲該任務棧的根Activity。
噹噹前的Activity啓動另一個Activity時,這個新的Activity被壓入到任務棧的棧頂。前一個Activity仍在任務棧裏,只是被標記爲停止狀態。當一個Actvity停止,系統保持着用戶交互的當前狀態。當點擊返回鍵時,當前的Activity從任務棧的棧頂彈出(該Activity被銷燬),之前的Activity恢復。Activity絕不會在任務棧中重新排列,僅會將啓動的Activity壓入棧中,將點擊返回鍵後的Activity彈出棧中。下圖展示了Activity在時間進程上的行爲:
如果用戶持續點擊返回鍵,則每次在棧頂的Activity會被彈出且展示之前的Activity,直到返回到主界面。當所有的Activity都從任務棧中移除,該任務不再存在。
當用戶開啓一個新的任務或通過Home鍵回到主屏幕時,任務作爲一個整體的單元被移動到後臺。當處於後臺,該任務棧中所有Activity被停止,但任務棧仍在,其只是簡單地失去了焦點。如下圖所示:
當用戶重新拉起應用,則其任務會重新回到前臺。
注意後臺可以同時保持多個任務。但是,如果用戶在後臺同時運行着多個任務,則系統可能會銷燬後臺的Activity以回收內存,這會是這些Activity的狀態丟失(關於更多狀態保持與恢復的內容,請查看Android狀態保存與恢復)。
因爲在任務棧中的Activity絕不會重新排列,所以如果應用運行用戶啓動一種具體的Activity多餘一個,則這種Activity的新的實例將被創建並壓入任務棧中,而不是將之前的該Activity的實例移到棧頂。像這樣,你的應用中的一個Activity可能會被實例化多次,甚至是在不同的任務棧中。如下圖所示:
然而,如果你不想一個Activity被實例化多次,則可以修改這種行爲。這將在後面的“管理任務棧”一節講到。
下面總結一下Activity和任務的默認行爲:
- 當Activity A啓動Activity B,Activity A停止,但系統仍會保持它的狀態。如果用戶在Activity B點擊了返回鍵,則Activity A從保存的狀態中恢復。
- 當用戶通過點擊Home鍵離開任務,當前Activity停止且它的任務棧調度到後臺。系統保持了任務棧中每一個Activity的狀態。如果隨後用戶點擊了桌面圖標,則該任務會被調度到前臺並且恢復棧頂的Activity。
- 如果用戶點擊了返回鍵,當前Activity將從任務棧中彈出並被銷燬。在棧中的之前的Activity會被恢復。
- Activity可以被實例化多次,且可以在不同任務棧中。
管理任務棧
同上面的描述,Android管理任務和回退棧的方式是將連續啓動的Activity放置在同一任務棧中,對於大多數的應用,這可以工作的很好,你不需要擔心你的Activity和任務之間是怎樣關聯的或它們是怎樣存在於任務棧中的。然而,你可以決定是否打斷這種正常的行爲。也許你想你的應用中的一個Activity在啓動時創建一個新的任務,或是,當啓動一個Activity時,你想將一個已經存在的實例移到棧頂,再或是,你想在離開任務時,將任務棧中除root Activity中的所有activity清除。
你可以使用manifest中的<activity>
元素的屬性或傳遞到startActivity()
的Intent中的flags,來實現這些需求。
與其相關的,主要的<activity>
屬性如下:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
與其相關的主要的Intent flags有:
- FLAG_ACTIVITY_NEW_TASK
- FLAG_ACTIVITY_CLEAR_TOP
- FLAG_ACTIVITY_SINGLE_TOP
在下一節中,將給出怎樣使用<activity>
屬性和Intent flags來定義activity和任務之間的關係與它們在回退棧中的行爲表現。
注意,大部分應用不應該打斷Activity和任務之間的默認行爲。如果你認爲修改默認行爲是必要的,那一定要測試該Activity的使用情況是否如你所願,以確保其不會打斷用戶期待的行爲。
定義啓動模式
啓動模式允許你定義一個Activity的新實例怎樣與當前任務關聯。你可以用下面兩種方式定義啓動模式:
使用manifest文件
當你在manifest文件中聲明Activity時,你可以定義其啓動時與任務的關聯方式。
具體可以使用<activity>
元素的lauchMode屬性來定義該Activity應該怎樣在任務中創建。有四種不同啓動模式可以設置給lauchMode屬性。
standard
默認設置。每次啓動該種Activity時,系統在任務中創建一個新的Activity實例。這種Activity能夠被實例化多次,每個實例屬於不同的任務,每個任務可以有多個實例。singleTop
如果該Activity的一個實例存在與當前任務棧的棧頂,系統將啓動Intent通過onNewIntent()
傳遞給該實例,而不會新建實例。如果已有該實例不在棧頂,則會新建實例。該Activity會被實例化多次,每個實例可以屬於不同的任務,每個任務可以有多個實例。
注意,當該Activity的一個新實例被創建,用戶可以點擊返回鍵回到之前的Activity。但當一個Activity的已存在實例處理了這個啓動Intent時,用戶點擊返回鍵不能回到調用onNewIntent()
進行處理之前的狀態。singleTask
該種啓動模式的Activity僅會有一個實例。如果已有任務棧中存在該Activity實例,則系統會將啓動它的Intent通過調用其onNewIntent()
方法傳遞給它,而不會再創建一個新的實例,且該Activity上面的所有Activity將以合適的方式自動銷燬。如果還沒有該Activity實例,則其表現受taskAffinity
屬性影響,如果taskAffinity
屬性標識的任務不存在,則會新建一個任務,並將該Activity作爲根Activity,如果taskAffinity
屬性標識的任務存在,則將該Activity壓入該任務棧。
注意,儘管Activity會被啓動在一個新的任務中,點擊返回鍵仍然能返回到之前的Activity。singleInstance
除了系統不會再將其他Activity放入該Activity所在任務,其他同singleTask
一樣。即該Activity是其所在任務的唯一成員,任何由它啓動的Activity將被放置在分隔的任務棧中。
不管一個Activity是否啓動在一個新的任務中還是在與啓動它的Activity相同的任務棧中,點擊返回鍵時,都會回到前一個Activity。然而,如果你啓動的是singleTask
模式的Activity,且如果其實例存在於後臺,則整個任務會被帶到前臺。這時,回退棧將包含所有從後臺帶到前臺的Activity,並且被放置在棧頂。如下圖所示:
使用Intent flag
當你調用startActivity()
時,你可以在Intent中設置flag來聲明啓動的Activity與任務的關聯方式。
像這樣,如果Activity A啓動了Activity B,Activity B能在manifest中定義它應該與當前任務棧怎樣關聯,並且Activity A也可以請求Activity B怎樣與當前任務關聯。如果兩個全部定義了,則Activity A的請求是優於Activity B的請求。
可以用來修改默認行爲的flag有:
FLAG_ACTIVITY_NEW_TASK
其行爲同launchMode設置爲“singleTask”。FLAG_ACTIVITY_SINGLE_TOP
其行爲同launchMode設置爲“singleTop”。FLAG_ACTIVITY_CLEAR_TOP
如果被啓動的Activity已經存在於當前任務中,則其上的所有Activity都被銷燬,啓動Intent傳遞到onNewIntent()
方法,來恢復該Activity。
沒有對應的launchMode屬性。
FLAG_ACTIVITY_CLEAR_TOP經常和FLAG_ACTIVITY_NEW_TASK一起使用。當它們一起使用時,這些flags是將一個已經存在的Activity放置到另一個任務中,並將其放在一個能響應該Intent的位置上。
注意,如果被指定的Activity的啓動模式是“standard”,則它將從任務棧中移除,並在它的位置處創建一個新的實例來處理這個Intent。這是因爲,當啓動模式是“standard”時,對於每一個新的Intent都會創建一個新的實例。
注意,manifest中可獲取的啓動模式不一定在Intent的flag中可獲取,同樣的,Intent的flag中可獲取的啓動模式在manifest中不一定可以定義。
處理關係
“關係”指示一個Activity屬於哪個任務。默認的,所有來自同一個應用程序的Activity有相同的“關係”。所以默認情況下,同一應用程序的所有Activity屬於統一任務。但是,你可以修改一個Activity的關係。在不同應用程序的Activity可以共享同一個“關係”,同一應用程序的的Activity可以分配不同的“關係”。
可以使用<activity>
元素的taskAffinity
屬性來修改給定Activity的“關係”。
taskAffinity
屬性的值是一個字符串。系統使用包名來標識一個應用程序的默認任務“關係”。爲一個activity的taskAffinity設置一個空字符串,表明這個activity不屬於任何task。
“關係”用於下面兩種情況:
當創建Activity的Intent包含FLAG_ACTIVITY_NEW_TASK標籤時。
默認情況下,一個新的Activity被創建在調用startActivity()
方法的Activity所在任務中。它被壓入調用者所在的回退棧中。然而,如果傳遞到startActivity()
方法中的Intent的包含FLAG_ACTIVITY_NEW_TASK標籤,則系統會根據條件找尋一個合適的任務來放置這個新的Activity。通常,它是一個新的任務。但是,不總是。如果已經存在一個與這個新的Activity標識的“關係”相同的任務,則這個Activity被創建到這個任務中。否則,啓動一個新任務。
有些實體(比如通知欄管理器)會一直在一個外部任務中啓動Activity,所以它們一直在傳遞到startActivity()
方法中的Intent中設置FLAG_ACTIVITY_NEW_TASK標籤。如果你有一個Activity被外部使用啓動,則可能使用了這個標籤,注意這是用戶有獨立的方式返回到啓動它的任務,比如點擊桌面圖標。當Activity的
allowTaskReparenting
屬性設置爲true時。
這種情況下,當該Activity標識的“關係”的任務返回到前臺時,該Activity可以從啓動它的任務移動到同其“關係”的任務中。
例如,假設一個報導天氣條件的Activity被定義爲一個旅遊應用的一部分,且其具有其所在應用程序的其他Activity相同的“關係”(應用程序的默認關係)並允許使用allowTaskReparenting
屬性設置允許re-pareting。當你的Activity之一啓動了這個天氣預報Activity時,它初始屬於你的Activity的任務。但是,當這個旅遊應用的任務返回前臺時,這個天氣預報Activity被重新安排到旅遊應用的任務中並展示它。
清理回退棧
如果用戶長時間離開一個任務,則系統會清理掉任務中除根Activity之外的所有Activity。但用戶再次回到任務中,僅根Activity是被恢復。系統表現這種行爲的原因是,用戶離開很久後,可能已經放棄了他們之前正在進行的操作,所以返回到任務開始一個新的操作。
有很多的Activity屬性可以用來修改這個行爲:
alwaysRetainTaskState
如果任務中的根Activity的這個屬性被設置爲true,則上面被描述的默認行爲不會發生。很長一段時間後,該任務仍保持所有Activity。clearTaskOnLaunch
如果任務中的根Activity的這個屬性被設置爲true,則當用戶離開任務並返回時,該任務棧被清理直到根Activity。用戶會一直以初始狀態返回任務,甚至只是離開一小會。finishOnTaskLaunch
這個屬性很像clearTaskOnLaunch
,但它操作在一個單獨的Activity上,而不是整個任務上。它會導致任何Activity銷燬,包括根Activity。當它被設置爲true,該Activity僅存在當前會話任務中。如果用戶離開後返回該任務,則它不在存在。
啓動任務
可以通過給一個Activity設置”android.intent.action.MAIN”和”android.intent.category.LAUNCHER”Intent 過濾器來將其設置爲一個任務的入口。例如:
<activity ... >
<intent-filter ... >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
...
</activity>
這種類型的Intent過濾器會爲該Activity產生一個圖標和標籤展示在應用程序啓動器中,以提供給用戶一個方式去創建該Activity或在它創建後可以任意次回到其創建的任務。
其第二個能力是重要的:用戶必須能夠在離開任務後,又能使用該Activity啓動器回到它。因爲這個原因,作爲啓動器的Activity應該僅在該Activity有ACTION_MAIN 和CATEGORY_LAUNCHER過濾器時,才使用singleTask
和singleInstance
這兩個啓動模式。例如,如果這兩個過濾器沒有添加,一個Intent創建了一個singleTask
Activity,初始化了一個任務,且用戶在該任務上執行了很多操作,這時用戶點擊Home鍵。這個任務被放到後臺不可見,這時用戶沒有了返回到這個任務的方法。這是因爲,它不會顯示在應用程序啓動器中。
回退任務
在啓動一系列Activity後,可能會創建幾個任務,其中每個任務在回退棧中作爲一項,在用戶點擊返回鍵時,回退棧的默認回退情況(爲對返回鍵處理重寫等)是,先獲得回退棧中棧頂的任務,然後彈出該任務棧棧頂的Activity實例,當該任務棧中的所有Activity實例都被彈出,則該任務從回退棧中彈出,並銷燬,執行這個回退過程,直到回退到桌面。
四種啓動模式的關鍵結論驗證
launchMode:standard
standard
是默認的啓動模式,所以Activity不設置launchMode,則其啓動模式爲standard
。
被啓動Activity和啓動Activity的taskAffinity相同
FirstActivity註冊
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
SecondActivity註冊
<activity android:name=".SecondActivity" />
驗證1:該種Activity不啓動新的任務,被啓動的Activity被壓入啓動它的Activity所在的任務棧中
執行FirstActivity啓動SecondActivity。
任務棧情況(執行adb shell dumpsys activity
)
TaskRecord{27db6384 #3208 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity (has extras) }
Hist #1: ActivityRecord{395c8c83 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3208}
Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{cd3c76d 16254:com.example.sunxiaodong.taskandbackstack/u0a379}
Hist #0: ActivityRecord{3240b0d0 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3208}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity (has extras) }
ProcessRecord{cd3c76d 16254:com.example.sunxiaodong.taskandbackstack/u0a379}
從任務棧情況可以得到,SecondActivity被壓入FirstActivity所在的任務棧中。
驗證2:每次啓動該種Activity,系統會在任務中創建一個新的Activity實例
執行FirstActivity啓動SecondActivity,SecondActivity中再次啓動SecondActivity。
任務棧情況(執行adb shell dumpsys activity
)
TaskRecord{2ab63d02 #3211 A=com.example.sunxiaodong.taskandbackstack U=0 sz=3}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #2: ActivityRecord{3c598601 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3211}
Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{18925050 13122:com.example.sunxiaodong.taskandbackstack/u0a379}
Hist #1: ActivityRecord{2d1693 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3211}
Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{18925050 13122:com.example.sunxiaodong.taskandbackstack/u0a379}
Hist #0: ActivityRecord{ddb9d9 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3211}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{18925050 13122:com.example.sunxiaodong.taskandbackstack/u0a379}
從任務棧情況可以得到,任務棧中已存在SecondActivity實例的情況下,再啓動SecondActivity還會創建一個新的SecondActivity實例壓入棧頂。
被啓動Activity和啓動Activity的taskAffinity不同
驗證1:如果被啓動Activity的taskAffinity所標識的任務不存在,則該種Activity不能創建新任務
FirstActivity註冊
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
SecondActivity註冊
<activity
android:name=".SecondActivity"
android:taskAffinity="com.example.sunxiaodong.taskandbackstack.second" />
執行FirstActivity啓動SecondActivity。
任務棧情況(執行adb shell dumpsys activity
)
TaskRecord{1abd4247 #3369 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #1: ActivityRecord{17e1a735 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3369}
Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{1c02e7c3 18114:com.example.sunxiaodong.taskandbackstack/u0a387}
Hist #0: ActivityRecord{3d5eef14 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3369}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{1c02e7c3 18114:com.example.sunxiaodong.taskandbackstack/u0a387}
從任務棧情況得到,standard
啓動模式的Activity不會創建taskAffinity標識的新的任務。
驗證2:如果被啓動Activity的taskAffinity所標識的任務已存在,則被啓動Activity的實例會放入啓動其Activity所在任務棧中,而不管啓動Activity是否在被啓動Activity的taskAffinity標識任務中
FirstActivity註冊
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
SecondActivity註冊
<activity
android:name=".SecondActivity"
android:launchMode="singleTask"
android:taskAffinity="com.example.sunxiaodong.taskandbackstack.second" />
ThirdActivity註冊
<activity android:name=".ThirdActivity" />
執行FirstActivity啓動SecondActivity,SecondActivity啓動ThirdActivity。
任務棧情況(執行adb shell dumpsys activity
)
Task id #3374
TaskRecord{1ac34ecf #3374 A=com.example.sunxiaodong.taskandbackstack.second U=0 sz=2}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
Hist #1: ActivityRecord{18fa9f27 u0 com.example.sunxiaodong.taskandbackstack/.ThirdActivity t3374}
Intent { cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }
ProcessRecord{3c0de43a 29526:com.example.sunxiaodong.taskandbackstack/u0a387}
Hist #0: ActivityRecord{43cba37 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3374}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{3c0de43a 29526:com.example.sunxiaodong.taskandbackstack/u0a387}
Task id #3372
TaskRecord{2a45d05c #3372 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #0: ActivityRecord{253e4bf4 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3372}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{3c0de43a 29526:com.example.sunxiaodong.taskandbackstack/u0a387}
任務棧情況,符合驗證的結論。
launchMode:singleTop
FirstActivity註冊
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
SecondActivity註冊
<activity
android:name=".SecondActivity"
android:launchMode="singleTop" />
驗證1:被啓動Activity在啓動其Activity所在任務棧的棧頂,則不會創建被啓動Activity的新實例
執行FirstActivity啓動SecondActivity,SecondActivity再啓動SecondActivity。
任務棧情況(執行adb shell dumpsys activity
)
TaskRecord{35412fbd #3376 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #1: ActivityRecord{1fbbf35c u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3376}
Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{11ea5d03 30105:com.example.sunxiaodong.taskandbackstack/u0a387}
Hist #0: ActivityRecord{3456a7b u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3376}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{11ea5d03 30105:com.example.sunxiaodong.taskandbackstack/u0a387}
從任務棧情況得到,啓動模式爲singleTop
的被啓動Activity在啓動其Activity所在任務棧的棧頂時,不會創建新實例。
驗證2:被啓動Activity不在啓動其Activity所在任務棧的棧頂,則會在啓動Activity所在任務棧的棧頂創建新的被啓動Activity實例
ThirdActivity註冊
<activity
android:name=".ThirdActivity"
android:launchMode="singleTask"
android:taskAffinity="com.example.sunxiaodong.taskandbackstack.third" />
執行FirstActivity啓動SecondActivity,SecondActivity啓動ThirdActivity,ThirdActivity再啓動SecondActivity。
任務棧情況(執行adb shell dumpsys activity
)
Task id #3381
TaskRecord{20eb4d89 #3381 A=com.example.sunxiaodong.taskandbackstack.third U=0 sz=2}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }
Hist #1: ActivityRecord{1fdcca07 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3381}
Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{163795bc 11943:com.example.sunxiaodong.taskandbackstack/u0a387}
Hist #0: ActivityRecord{1cdc6d17 u0 com.example.sunxiaodong.taskandbackstack/.ThirdActivity t3381}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }
ProcessRecord{163795bc 11943:com.example.sunxiaodong.taskandbackstack/u0a387}
Task id #3379
TaskRecord{36c5f18e #3379 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #1: ActivityRecord{3fc54f79 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3379}
Intent { cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{163795bc 11943:com.example.sunxiaodong.taskandbackstack/u0a387}
Hist #0: ActivityRecord{104fbd9a u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3379}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{163795bc 11943:com.example.sunxiaodong.taskandbackstack/u0a387}
啓動模式爲singleTop
的其他啓動情況與啓動模式爲standard
的情況相同,不再給出驗證。
launchMode:singleTask
驗證1:如果被啓動Activity的taskAffinity屬性標識的任務爲啓動Activity所在任務,則不會新建任務
FirstActivity註冊
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
SecondActivity註冊
<activity
android:name=".SecondActivity"
android:launchMode="singleTask" />
執行FirstActivity啓動SecondActivity。
任務棧情況(執行adb shell dumpsys activity
)
TaskRecord{220c4e08 #3406 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #1: ActivityRecord{2606f228 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3406}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{1ced3387 30484:com.example.sunxiaodong.taskandbackstack/u0a387}
Hist #0: ActivityRecord{27f048cb u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3406}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{1ced3387 30484:com.example.sunxiaodong.taskandbackstack/u0a387}
從任務棧情況可以得到,啓動模式爲singleTask
的Activity並不是每次啓動都會新建任務,當其taskAffinity屬性所標識的任務爲啓動Activity所在任務時,不會新建任務,即其taskAffinity屬性所標識的任務已存在時,不會創建新的任務。
驗證2:如果被啓動Activity的taskAffinity屬性標識的任務不存在,則會新建任務
SecondActivity註冊
<activity
android:name=".SecondActivity"
android:launchMode="singleTask"
android:taskAffinity="com.example.sunxiaodong.taskandbackstack.second" />
執行FirstActivity啓動SecondActivity。
任務棧情況(執行adb shell dumpsys activity
)
Task id #3410
TaskRecord{3298bcfc #3410 A=com.example.sunxiaodong.taskandbackstack.second U=0 sz=1}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
Hist #0: ActivityRecord{1c628411 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3410}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{1ed6d60b 23610:com.example.sunxiaodong.taskandbackstack/u0a387}
Task id #3409
TaskRecord{3b856f85 #3409 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #0: ActivityRecord{29642a8a u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3409}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{1ed6d60b 23610:com.example.sunxiaodong.taskandbackstack/u0a387}
從任務棧情況可以得到,如果被啓動Activity的taskAffinity屬性標識的任務不存在,則會新建任務。
驗證3:如果被啓動Activity在棧中上面還有其他Activity實例,則這些Activity將以合適的方式自動銷燬
FirstActivity註冊
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
SecondActivity註冊
<activity
android:name=".SecondActivity"
android:launchMode="singleTask"
android:taskAffinity="com.example.sunxiaodong.taskandbackstack.second" />
ThirdActivity註冊
<activity android:name=".ThirdActivity" />
FourthActivity註冊
<activity
android:name=".FourthActivity"
android:launchMode="singleTask"
android:taskAffinity="com.example.sunxiaodong.taskandbackstack.fourth" />
執行FirstActivity啓動SecondActivity,SecondActivity啓動ThirdActivity,ThirdActivity啓動FourthActivity。
任務棧情況(執行adb shell dumpsys activity
)
Task id #3416
TaskRecord{36ee9249 #3416 A=com.example.sunxiaodong.taskandbackstack.fourth U=0 sz=1}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FourthActivity }
Hist #0: ActivityRecord{252b608a u0 com.example.sunxiaodong.taskandbackstack/.FourthActivity t3416}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FourthActivity }
ProcessRecord{22850a05 3430:com.example.sunxiaodong.taskandbackstack/u0a387}
Task id #3415
TaskRecord{19cb74e #3415 A=com.example.sunxiaodong.taskandbackstack.second U=0 sz=2}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
Hist #1: ActivityRecord{18f7b294 u0 com.example.sunxiaodong.taskandbackstack/.ThirdActivity t3415}
Intent { cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }
ProcessRecord{22850a05 3430:com.example.sunxiaodong.taskandbackstack/u0a387}
Hist #0: ActivityRecord{1d6f71ff u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3415}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{22850a05 3430:com.example.sunxiaodong.taskandbackstack/u0a387}
Task id #3413
TaskRecord{3e8006f #3413 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #0: ActivityRecord{1648bf23 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3413}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{22850a05 3430:com.example.sunxiaodong.taskandbackstack/u0a387}
從任務棧情況可知,當前有3個任務,其中SecondActivity和ThirdActivity 在一個任務中,且ThirdActivity的實例在SecondActivity的實例之上。
接着上面,執行FourthActivity啓動SecondActivity。
任務棧情況(執行adb shell dumpsys activity
)
Task id #3419
TaskRecord{20698cd0 #3419 A=com.example.sunxiaodong.taskandbackstack.second U=0 sz=1}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
Hist #0: ActivityRecord{28bfef87 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3419}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{722a5fc 10546:com.example.sunxiaodong.taskandbackstack/u0a387}
Task id #3421
TaskRecord{2eb884c9 #3421 A=com.example.sunxiaodong.taskandbackstack.fourth U=0 sz=1}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FourthActivity }
Hist #0: ActivityRecord{cd70e2d u0 com.example.sunxiaodong.taskandbackstack/.FourthActivity t3421}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FourthActivity }
ProcessRecord{722a5fc 10546:com.example.sunxiaodong.taskandbackstack/u0a387}
Task id #3418
TaskRecord{197bf7ce #3418 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #0: ActivityRecord{270d8dc9 u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3418}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{722a5fc 10546:com.example.sunxiaodong.taskandbackstack/u0a387}
從任務棧的情況可知,SecondActivity啓動後,其所在任務中的ThirdActivity銷燬了,SecondActivity被放置在了棧頂。
launchMode:singleInstance
FirstActivity註冊
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
驗證1:該種Activity的任務中,只會有一個實例,且由該種Activity啓動Activity,如果被啓動Activity的taskAffinity屬性標識的任務存在,則將實例壓入該任務中,如果不存在,則新建該任務
ThirdActivity註冊
<activity android:name=".ThirdActivity" />
執行FirstActivity啓動SecondActivity,SecondActivity啓動ThirdActivity。
任務棧情況(執行adb shell dumpsys activity
)
Task id #3423
TaskRecord{193241ab #3423 A=com.example.sunxiaodong.taskandbackstack U=0 sz=2}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #1: ActivityRecord{1b89f8e8 u0 com.example.sunxiaodong.taskandbackstack/.ThirdActivity t3423}
Intent { flg=0x10400000 cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }
ProcessRecord{92fe3a1 13471:com.example.sunxiaodong.taskandbackstack/u0a387}
Hist #0: ActivityRecord{26f251dd u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3423}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{92fe3a1 13471:com.example.sunxiaodong.taskandbackstack/u0a387}
Task id #3425
TaskRecord{304529c6 #3425 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
Hist #0: ActivityRecord{2f0cb55d u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3425}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{92fe3a1 13471:com.example.sunxiaodong.taskandbackstack/u0a387}
從任務棧中情況可知,SecondActivity啓動的ThirdActivity的taskAffinity屬性標識的任務存在,則不再新建任務,而是將其壓入已存在的任務中。
ThirdActivity註冊
<activity
android:name=".ThirdActivity"
android:taskAffinity="com.example.sunxiaodong.taskandbackstack.third" />
給上面的ThirdActivity設置android:taskAffinity屬性後,執行FirstActivity啓動SecondActivity,SecondActivity啓動ThirdActivity。
任務棧情況(執行adb shell dumpsys activity
)
Task id #3430
TaskRecord{666e0ca #3430 A=com.example.sunxiaodong.taskandbackstack.third U=0 sz=1}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }
Hist #0: ActivityRecord{a8a6e49 u0 com.example.sunxiaodong.taskandbackstack/.ThirdActivity t3430}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.ThirdActivity }
ProcessRecord{3d776eb1 21693:com.example.sunxiaodong.taskandbackstack/u0a387}
Task id #3429
TaskRecord{3887723b #3429 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
Hist #0: ActivityRecord{d159cd9 u0 com.example.sunxiaodong.taskandbackstack/.SecondActivity t3429}
Intent { flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.SecondActivity }
ProcessRecord{3d776eb1 21693:com.example.sunxiaodong.taskandbackstack/u0a387}
Task id #3427
TaskRecord{1d7a3f96 #3427 A=com.example.sunxiaodong.taskandbackstack U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
Hist #0: ActivityRecord{2cc6f9c u0 com.example.sunxiaodong.taskandbackstack/.FirstActivity t3427}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.sunxiaodong.taskandbackstack/.FirstActivity }
ProcessRecord{3d776eb1 21693:com.example.sunxiaodong.taskandbackstack/u0a387}
從任務棧中情況可知,SecondActivity啓動的ThirdActivity的taskAffinity屬性標識的任務不存在,則會新建任務。