Activity LaunchMode
LaunchMode
Android中Activity的啟動模式有四種:
- standard(默認選項)
- singleTop
- singleTask
- singleInstance
可以在AndroidManifest.xml中通過指定activity標簽的android:launchMode屬性來改變:
<activity android:name=".SecondActivity"
android:launchMode="singleTop"/>
如果不指定launchMode屬性,那么activity會使用默認(standard)模式來運行
standard
standard是Activity的默認屬性,Android在啟動standard的Activity時遵循以下規則:
- 如果是點擊圖示進行啟動,則會新創建一個
task,然后將這個Activity壓入這個task中 - 如果是使用
startActivty進行啟動,則會將這個Activity壓入啟動它的那個Task中 - 默認情況下,Activity是多例模式,即一個Activity可以同時存在多個實體,也可以同時存在于多個
task中
詳細說明
Activity的standard模式在自己App內部通常表示沒有特殊的式樣要求,遵循系統默認情況即可, 但是在多個App之間使用的時候需要注意, 它會被壓入啟動他的那個App的task中, 例如: 在電話App中選擇添加聯系人操作, 此時啟動的是聯系人App的添加聯系人Activity,此時添加聯系人Activity會被壓入到電話App中,在用戶看來,就好像是這個頁面是屬于電話App的.
因為從整個業務流程來看, 用戶此時的心理預期是:
整個操作都屬于
電話App的流程, 而與聯系人app無關
此時Android系統的表現為:
添加聯系人頁面的入場影片為Activity進入的影片,而不是task切換的影片(未指定影片的情況下)- 當用戶點擊
多任務鍵時, 在后臺也看不到聯系人App, 只能看到電話app - 在
添加聯系人頁面中點擊回傳鍵,頁面會回退到電話App的頁面 - 如果此時用戶手動打開了
聯系人App, 并再次添加聯系人, 會得到一個全新的添加聯系人頁面, 并且與電話App中的`添加聯系人頁面沒有沖突

singleTop
singleTop整體的行為與standard一致,區別如下:
- 當Activity在入堆疊時,singleTop會檢測當前task的堆疊頂Activity,如果當前的堆疊頂Activity與要壓入的Activity是同一個Activity時,那么就不會創建Activity新的實體,而是會直接使用當前的堆疊頂Activity,并且會呼叫Activity的
onNewIntent方法,將新的Intent傳入
singleTop只會檢測堆疊頂的Activity,保證Activity在堆疊頂唯一,但是Activity還是可以以多例存在的
例如:
AActivity被設定為singleTop,AActivity啟動自己,或其它應用繼續啟動AActivity,此時:
-
AActivity在堆疊頂, 則不會創建AActivity,而是會呼叫AActivity的
onNewIntent方法

-
AActivity不在堆疊頂, 則會重新創建一個AActivity的實體, 并執行其
onCreate方法

singleTask
被標記為singleTask的Activity可以讓該Activity在被別的Activity啟動時,不會進入啟動他的Task中,而是會在屬于它自己的Task里創建,并放在堆疊頂, 然后把整個Task一起拿過來,壓在啟動Task上.
是否在當前Task中啟動Activity,主要看taskAffinity:
- 如果新的Activity的taskAffinity和當前Task相同,就繼續在當前Task啟動
- 如果不同,就換到別的Task,如果有則利用那個task,如果沒有就創建一個,找到對應task后:
- 如果目標Task里沒有目標Activity,創建Activity,入堆疊
- 如果目標Task中已有目標Activity,那么就將這個堆疊中在目標Activity上面的Activity全部銷毀,讓目標Activity出現在堆疊頂,然后呼叫他的onNewIntent()方法
singleInstance
整體行為與singleTask類似,但是有以下區別:
- 啟動singleInstance的Activity的時候,不管新Activity和當前Task的taskAffinity是否一樣,都會創建他獨有的Task
- 在singleInstance的Activity上啟動其他Activity時,無論二者的taskAffinity是否一樣,都不允許其他Activity進入當前task
即singleTask的Activity只會單獨存在在一個task中, 并且這個task中不能有其他的Activity,強調其獨占性
taskAffinity
taskAffinity代表的是task的相關性,可以認為是Android想要將同一個邏輯鏈條中的Activity放入統一個Task中,在Android中,不同task的taskAffinity是可以相同的
指定TaskAffinity
可以在AndroidManifest中通過android:taskAffinity屬性指定Activity所在task的taskAffinity

- 如果Activity沒有指定taskAffinity,那么就會使用application的taskAffinity
- 如果Application沒有指定taskAffinity, 那么就會使用應用的包名作為taskAffinity
最近任務
按下Android中的多任務鍵,會進入多任務頁面,多任務頁面中顯示的實際上是所有的task,并不是應用,當有多個task具有相同的taskAffinity是,最近任務串列里只會顯示最近新展示過的一個,所以如果標記了singleInstanse的Activity,完全有可能不顯示在多任務頁面中
例如:
AActivity標記為singleInstance,AActivity啟動了本應用的BActivity,此時AActivity和BActivity就會分別處于不同的task堆疊中,但是這兩個堆疊的taskAffinity都是應用的包名(默認情況下),此時點擊多任務頁面,只能看到BActivity的task,AActivity的task由于taskAffinity與BActivity的taskAffinity相同而被隱藏起來了
Task要不要在最近任務串列里顯示
上述的顯示規則,也可以被FLAG改變:
- FLAG_ACTIVITY_NEW_DOCUMENT: 添加了這個Flag的Activity,每個都會獨立顯示在最近任務里,但是關閉后,不會在最近任務里保留殘影
- FLAG_ACTIVITY_RETAIN_IN_RECENTS: 可以修改上面的規則,讓Activity在最近任務里保留殘影
- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:這個Activity從一開始就不會顯示在最近任務里,切走之后就再也切不回來了
回傳鍵
當點擊Android中的回傳鍵時,Android會按照以下邏輯進行執行:
- 對當前task執行出堆疊的操作,顯示出當前task的上一個Activity
- 如果當前task執行出堆疊后,沒有其他Activity,則銷毀這個task,但是并不會銷毀其在多任務頁面的快照
- 當前task銷毀后,如果有其他前臺task,則會切換到上一個前臺task
- 當前task銷毀后,如果沒有其他前臺task,則會直接顯示Home
所謂的前臺task,指的是再Activity運行程序中,使用startActivity的方式開啟了其他的task,這個時候這些新啟動的task就會以堆疊的形式組織起來,當一個task銷毀后,就可以顯示上一個task
但是,如果用戶按下了home鍵,或者多任務鍵后, 這些以堆疊形式組織起來的task就會被打散,用戶是無法通過回傳鍵再回到上一個task中.
例如:
- 在便簽應用中點擊網址,此時會啟動瀏覽器,這個時候前臺的task有兩個:便簽App的task和瀏覽器的task,每個task中只有一個Activity此時如果按下回傳鍵,會將瀏覽器的Task銷毀,然后頁面回到了便簽App
- 在便簽應用中點擊網址,此時會啟動瀏覽器,此時按下多任務鍵,然后再回到瀏覽器,此時,前臺的task就只剩下瀏覽器App一個了,這個時候按下回傳鍵,Android會銷毀瀏覽器的Task,然后回到Home上
更完整的場景分類
Activity的啟動,可以有很多分類方式:
打開的時候放進哪個Task
-
默認情況下(standard)以及singleTop,是屬于當前所屬的邏輯鏈條,即直接放入當前的task,而不去檢查taskAffinity
-
如果是singleTask,就需要判斷當前Activity和目標Activity的taskAffinity是否相同,相同就會放在當前task,不同就放入別的Task,而且在放進別的Task的時候,也會先嘗試找到一個和目標Activity的taskAffinity匹配的Task,找到就進入這個Task,找不到才會創建新的Task
總結起來,singleTask其實是個很簡單的規則: 查找taskAffinity相同的Task,找到就讓Activity進入,找不到就創建新的Task
而更本質上, 其實Activity啟動的時候,所有的launchMode都會 穿換成對應的Intent的
Flag(0個或多個都有可能),其中 singleTask會被轉換成好幾個Flag的疊加,其中一個就是Intent.FLAG_ACTIVITY_NEW_TASK,如果在startActivity 的時候,在Intent里添加上這個Flag:Intent intent = new Intent(this,MainActivity.class) ; intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);那么新Activity啟動時的入堆疊規則就會和配置了singleTask的 Activity一樣.
但是我們實際上也可以跳過這個搜索程序,如果在Intent里除了
FLAG_ACTIVITY_NEW_TASK之外,再配置上FLAG_ACTIVITY_MULTIPLE_TASK:Intent intent = new Intent(this,MainActivity.class) ; intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); startActivity(intent);那么Activity就會跳過搜索,直接創建一個新的Task來吧這個 Activity放在堆疊底
-
如果launchMode是singleInstance,并且目標Activity和當前的Activity不同,就放進新的單獨的Task;
- 另外,如果當前的Activity已經是singleInstance,那不管目標Activity是什么,只要二者不是同一個Activity,就會把目標Activity放進別的Task
打開的時候要不要清掉頂部的Activity
前面提到FLAG_ACTIVITY_NEW_TASK的入堆疊規則和singleTask一樣,同時singleTask會被轉換成多個Flag,而不只是FLAG_ACTIVITY_NEW_TASK,singleTask的行為規則除了入堆疊方面,還有清理頂部: 如果目標Activity已經在目標Task,但是不在堆疊頂,就會把上面的Activity全部清理掉.而這個清理頂部也是singleTask所對應的Flag之一:FLAG_ACTIVITY_CLEAR_TOP,需要將FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP配合在一起使用,才能達到類似singleTask那樣的清理頂部的效果,否則只有FLAG_ACTIVITY_CLEAR_TOP的話,Activity入堆疊時永遠會在堆疊頂,就沒有頂部可以清理了
打開時要不要復用已有的Activity
在singleTask的規則里, 如果目標Task里已經有了目標Activity,目標Activity頂部的其他Activiy會被清理掉,讓activity回到堆疊頂;而Intent.FLAG_ACTIVITY_CLEAR_TOP做的也是清理頂部的活,看起來好像一樣, 但是singleTask除了清理頂部,還會復用堆疊內的目標Activity,呼叫它的onNewIntent方法,這點和singleTop是一樣的,而Intent.FLAG_ACTIVITY_CLEAR_TOP并不會復用Activity,他的默認規則是:將目標Activity頂部的其他Activity,以及目標Activity一起,全部清理掉,然后重新啟動目標Activity到堆疊頂.
如果想在清理其他Activity的時候,別把目標Activity一起清掉,需要加上另一個flag:
FLAG_ACTIVITY_SINGLE_TOP
這個flag就是singleTop,所對應的唯一flag.
而singleTask其實對應了3個flag:FLAG_ACTIVITY_NEW_TASK+FLAG_ACTIVITY_CLEAR_TOP+FLAG_ACTIVITY_SINGLE_TOP,所以singleTask實際上就是這三個flag共同作用的規則:
- 讓Activity尋找和自己taskAffinity相同的Task(FLAG_ACTIVITY_NEW_TASK)
- 清理掉目標Activity頂部的其他Activity(FLAG_ACTIVITY_CLEAR_TOP)
- 復用堆疊中已有的目標Activity(FLAG_ACTIVITY_SINGLE_TOP)
實戰選擇
- standard和singleTop多用于App內部
- singleInstance:多用于開放給外部App來共享使用
- singleTask:內部互動和外部互動都會用得上
- 啟動Activiy盡量不要設定singleTask,因為這樣用戶每次點擊圖示的時候,都會將task中其他的Activiy全部殺死.即使配置了
clearTackOnLaunch = false也不能解決
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/204029.html
標籤:其他
上一篇:Codeforces Round #681 (Div. 2, based on VK Cup 2019-2020 - Final)
