系列文章:
前言
項目開發時,遇到了跳轉到另一Activity時,重復多次,然后退出時,需要多次返回才能退出,理想情況是雖然跳轉多次,但只需退出一次即可返回桌面,原因是Activity的啟動模式設置有誤。
因此為了給用戶良好的體驗,界面跳轉的啟動方式十分重要,除了在AndroidManifest.xml文件中指定launchMode外,通過設置Intent的一些標志(以FLAG_ACTIVITY_開頭)也可以新Activity的啟動模式。
Activity啟動模式
Task和Back Stack介紹
Task是在程序運行時只針對activity的概念。Task是一組相互關聯的activity的集合,它是存在于framework層的一個概念,控制界面的跳轉和返回。這個task存在于一個稱為back stack(棧)的結構中,即framework是以棧的形式管理用戶開啟的activity的。
參考:張紀剛 原文鏈接
四種啟動模式
默認情況下,當我們多次啟動同一個Activity時,系統會創建多個實例并把它們一一放入任務棧中,每按下back鍵就會有一個Activity出棧,直到棧空為止。
standard:標準模式
這是系統默認的模式,每次啟動一個新的Activity都會重新創建一個新的實例,不管這個實例已經是否存在。這種模式下,如果A啟動了B(標準模式),那么B自動進入A所在的任務棧中。
singleTop:棧頂復用模式 (登錄頁面、推送通知欄)
此種模式下,如果新Activity已經位于任務棧的棧頂,那么此Activity不會被重新創建,同時onNewIntent方法會被調用,通過此方法的參數獲取當前請求信息。而且,此Activity的
onCreate,onStart不會被調用,因為沒有發生改變。
- singleTop模式分3種情況:
- 當前棧中已有該Activity的實例并且該實例位于棧頂時,不會新建實例,而是復用棧頂的實例,并且會將Intent對象傳入,回調onNewIntent方法
- 當前棧中已有該Activity的實例但是該實例不在棧頂時,其行為和standard啟動模式一樣,依然會創建一個新的實例
- 當前棧中不存在該Activity的實例時,其行為同standard啟動模式
standard和singleTop啟動模式都是在原任務棧中新建Activity實例,不會啟動新的Task,即使你指定了taskAffinity屬性
singleTask:棧內復用模式(應用中展示的主頁(Home頁))
此種模式下,只要Activity在一個棧中存在,那么多次啟動此Activity都不會重新創建實例,系統會回調onNewIntent方法。系統會先尋找是否存在A想要的任務棧,如果不存在,就
重建一個任務棧,然后創建A的實例放入新任務棧中;如果存在A想要的任務棧,再查看是否有Activity實例存在,有的話就把該實例調到棧頂,如果實例不存在,則創建A的實例放入
任務棧中。下面舉三種例子說明此種模式運行機制:
- 目前任務棧S1中為ABC,Activity D以singleTask模式請求啟動,其需要的任務棧為S1,那么系統會創建D的實例,將D放入S1中
- 目前任務棧S1中為ABC,Activity D以singleTask模式請求啟動,其需要的任務棧為S2,那么系統會創建任務棧S2,再將D放入S2中
-
目前任務棧S1中為ADBC,Activity D以singleTask模式請求啟動,其需要的任務棧為S1,那么系統不會創建D的實例,將D切換到棧頂并調用其onNewIntent方法,同時棧內所有在D上
面的Activity都需要出棧,最終的S1為AD
ActivityLaunchMode_singleTask
singleInstance:單實例模式 (系統Launcher、鎖屏鍵、來電顯示等系統應用)
這是一種加強的singleTask模式,除了具有singleTask模式的所有特性外,具有此種模式的Activity只能單獨位于一個任務棧中。比如Activity A以singleInstance模式啟動,系統會
為其創建一個新的任務棧,然后A獨自運行在該任務棧中,后續的請求均不會創建新的Activity。
以singleInstance模式啟動的Activity具有獨占性,即它會獨自占用一個任務,被他開啟的任何activity都會運行在其他任務中(官方文檔上的描述為,singleInstance模式的Activity不允許其他Activity和它共存在一個任務中)
Intent Flags
上面的場景僅僅適用于Activity通過Intent啟動Activity,并且Intent沒有額外添加任何Flag,下面分析下幾個常用FLAG的作用。
當啟動模式與FLAG沖突時,以FLAG為準。
FLAG_ACTIVITY_NEW_TASK
該FlAG的作用可以分為兩類情形,一種是Activity啟動Activity,另一種是非Activity(如Service)啟動Activty。
singleTask和singleInstance這兩種啟動模式被預設置了Intent.FLAG_ACTIVITY_NEW_TASK,而standard及singletTop則不會設置。
非Activity啟動Activity時必須添加此Flag,這個FLAG的關注重點是TASK,設置此flag后,大多數情況下新啟動Activity就會被放置到自己taskAffinity的Task中。下面具體總結下:
- 目標Activity實例或者Task不存在,則一定會新建Activity,并將目標Task移動到前臺
- 目標Task存在,目標Activity不存在,則新建Activity,并將目標Task移動到前臺
- 目標Task存在,目標Activity存在,但是不是根Activity,則新建Activity
-
目標Task存在,目標Activity存在,且是根Activity,且intent和當前待啟動的intent相等,則只要將Task移動至前臺即可
ActivityLaunchMode_NewTask
FLAG_ACTIVITY_SINGLE_TOP
該FLAG的作用是為Activity指定"singleTop"啟動模式,其效果和在XML中指定該啟動模式相同
FLAG_ACTIVITY_CLEAR_TOP
具有此標志位的Activity,當它啟動時,在同一個任務棧中所有位于其上面的Activity都要出棧,這個標志一般和FLAG_ACTIVITY_NEW_TASK一起使用,具體可以分為以下幾種情況。
- 單獨使用,沒有設置特殊的launchMode,那么其任務棧中目標Activity及目標Activity之上的Activity都出棧
- 結合了FLAG_ACTIVITY_SINGLE_TOP,在目標Task和目標Activity都存在就不會重建,而是直接回調目標Activity的onNewIntent(),
- 結合了FLAG_ACTIVITY_NEW_TASK使用,如果目標Task存在一個Activity實例,則將其上面的及自身清理掉,之后重建
- 結合了FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_SINGLE_TOP使用,如果topActivity不是目標Activity,就會去目標Task中去找,并喚起;如果topActivity是目標Activity,就直接回調topActivity的onNewIntent,無論topActivity是不是在目標Task中
參考:看書的小蝸牛 原文鏈接
FLAG_ACTIVITY_CLEAR_TASK
這個屬性必須同FLAG_ACTIVITY_NEW_TASK配合使用,設置了這個FLAG后,如果目標task已經存在,將清空已存在的目標Task,否則,新建一個Task棧,再新建一個Activity作為根Activity。
Intent.FLAG_ACTIVITY_CLEAR_TASK的優先級最高,基本可以無視所有的配置,包括啟動模式及Intent Flag,哪怕是singleInstance也會被finish,并重建。
參考:看書的小蝸牛 原文鏈接
TaskAffinity
前文我們說過啟動Activity所需的任務棧,此參數標識了一個Activity所需要的任務棧的名字,默認情況下Activity所需要的任務棧為應用的包名。
TaskAffinity屬性主要和singleTask啟動模式或者allowTaskReparenting屬性配對使用,在其他情況下沒有意義。
- TaskAffinity和singleTask配合使用時,它是具有該模式的Activity的目前任務棧的名字
- TaskAffinity和allowTaskReparenting屬性配合使用時,當一個應用A啟動應用B的某個Activity后,如果這個Activity的allowTaskReparenting屬性為true的話,那么當應用B被啟動后,此Activity會直接從應用A的任務棧轉移到應用B的任務棧中