Android啟動activity的4種模式(standard、singleTop、singleTask、singleINstance)


在AndroidManifest.xml中配置activity時,android:launchMode屬性會指定啟動activity的模式,有四種:

standard

singleTop

singleTask

singleInstance

這四種模式一般配合Intent屬性變量FLAG_ACTIVITY_XXX使用,比如FLAG_ACTIVITY_NEW_TASK,本文暫時撇開FLAG_ACTIVITY_XXX,只討論這四種模式的啟動結果,先考慮只在同一個應用下的情況。

standard模式

系統默認情況下就是standard模式,假如A中設置為默認模式,A中有一個按鈕,單擊按鈕時只啟動自己,看看啟動后的結果。AndroidManifest.xml、A和源碼及布局分別為:

注:本文案例在小米4上測試

假設現在沒有運行程序,先通過命令dumpsys activity activities在串口中查看所有activity棧信息:

沒有啟動案例時的棧

看紅色區域,activity棧中只有一個代號為0的棧,棧中也只有一個id號為#1的task和id號為#0的ActivityRecord,ActivityRecord中保存的包名是com.miui.home,啟動類名為.launcher.Launcher,也就是說,目前Activity棧中只有Launcher應用,沒有別的應用。

現在啟動案例,啟動后的棧信息:

啟動案例后的棧

案例啟動后,系統新建了一個棧stack #1,其中有新啟動的Activity實例AActivity,保存在id號為#24的task中

然后,點擊按鈕再次啟動AActivity,啟動后的棧信息為:

再次啟動AActivity后的棧

在同樣的stack #1、同樣的task #24中多了一個AActicity實例,兩個實例對應的ActivityRecord地址不一樣,一個是42e23ae0,一個是42da3a08。

默認標准模式,每啟動一次,就創建一個新實例,並放到棧頂,並且該實例放在同樣的任務task中、同樣的activity棧中。不會再新創建棧、task。

singleTop模式

如果把A設為默認Standard標准模式,把B設置singleTop模式,A啟動B后看看什么情況,相關源碼較簡單,不再添加,本文后又源碼下載地址。

A啟動B后的棧

在stack #1中,新創建了一個task #25,包含B實例和A實例,新啟動的實例位於棧頂。如果在B中點擊按鈕再次啟動B,發現棧信息不會改變,而且無論點擊多少次按鈕,stack #1棧中還是B和A,不會重新創建實例。

假設在A中啟動B,B啟動C,C設為標准模式,啟動后的棧信息:

A啟動B,B啟動C后的棧

棧頂是C,其次是B和A,A在棧最底部;如果此時在C中點擊按鈕再啟動B呢?啟動后的棧信息:

A啟動B,B啟動C,C再次啟動B后的棧

發現棧頂又創建了一個B實例,不會復用棧中已有的實例,棧中總共有2個B實例!

singleTop模式跟標准Standard模式差不多,只不過多了一種情況,分為兩種情況來看:

1.  如果棧中已經有了待啟動activity實例並且位於棧頂,那么再次啟動該activity時,系統會直接復用該實例,不會再創建新的實例;如果沒有,就新創建實例,並放到棧頂;

2. 如果棧中已經有了待啟動activity實例,但不在棧頂,那么再次啟動該activity時,系統會再次創建新的實例並將該實例放到棧頂,這種情況和standard模式一樣。

singleTask模式

如果A和C設置standard模式,B設為singleTask模式,A啟動B,B啟動C,按照這個順序啟動后,棧中自底向上為:A—–B—–C,如果此時在C中點擊按鈕再次啟動B呢?啟動后棧信息為:

singleTask模式下A啟動B,B啟動C,C再次啟動B后的棧

此時,Task #30中只有A和B,B位於棧頂,沒有C了,這個和singleTop有了明顯的差別,在singleTop中C不會消失,而此時C卻消失了。

1.  如果棧中已經有了待啟動activity實例並且位於棧頂,那么再次啟動該activity時,系統會直接復用該實例,不會再創建新的實例;如果沒有,就新創建實例,並放到棧頂;

2. 如果棧中已經有了待啟動activity實例但不在棧頂,那么再次啟動該activity時,系統會復用已有實例,並且把位於該實例之上的所有其他activity實例移出棧,同時將該實例放在棧頂。

singleInstance模式

如果設A和C為standard模式,B為singleInstance模式,A啟動B后棧信息為:
singleInstance模式下A啟動B后的棧

發現和上面三種情況都不一樣的地方,在棧中新創建了一個task,並把B放入其中,上面三種情況都是在同樣的task中。如果再B中啟動C,啟動后的棧:

singleInstance模式下A啟動B后,B啟動C的棧

A和C都是標准模式,都在同一個task中,而B在另外一個task中,因為啟動了C,C在棧頂。如果再C中點擊按鈕再次啟動B,結果會是什么?

singleInstance模式下A啟動B后,B啟動C,C再啟動B的棧

B所在的task跑到了棧頂,A和C所在的task在棧底。而且B始終只有一個實例。

1.  如果棧中沒有待啟動activity實例,啟動該activity時,系統會新創建一個task,再創建一個待啟動activity實例,把該實例放到新task中,並且該task會在棧頂;

2. 如果棧中已經有了待啟動activity實例,不管在棧的什么位置,系統都會復用已存在實例,並且把該實例放在棧頂,而且該task中只有一個該實例,不會再有第二個實例,也不會有其他activity實例;

3. 如果一個應用中有多個activity都設置成singleInstance模式,那么每個啟動后的activity實例都保存在一個task中,不會在同一個task中,task和實例是一對一關系。

同一應用中測試小結

a. standard、singleTop存在多種實例的可能(“可能”二字表明,singleTop情況下,如果棧頂已有實例,再次啟動時只會復用,如果不在棧頂,就會新創建實例);而singleTask和singleInstance只有一個實例,再次啟動時不會創建新實例;

b. singleTask和singleInstance模式,再次調用時都會先調用onNewIntent方法,再調用onResume方法;對於singleTop,如果棧頂已有實例,也是先調用onNewIntent方法,再調用onResume方法,如果不在棧頂或者還沒有實例,就會先調用onCreate方法;

c. singleInstance模式不同於其他三種,首次啟動時會新開啟一個task,該task只包含一個實例;再次啟動時只會復用該task,不再新創建。

同一應用中只有1個app,源碼地址:https://yunpan.cn/crybfHCWhcbwW  訪問密碼:e7cb

 

不同應用之間測試小結

上面分析了在同一應用中的情況,再看看不同應用之間的情形。通過測試得知:standard、singleTop沒有什么改變,還是在在同樣的棧、task中;singleInstance模式下也沒有改變,還是會創建新的task並保存唯一實例;但singleTask卻不一樣,首次啟動時,系統會在當前棧中創建一個新的task,再次啟動時,復用已有task;而在同一應用中,再次啟動時,不會再創建新task的,直接復用已有task。

不同應用之間測試有2個app,源碼地址:https://yunpan.cn/crKLt2CuZ7drc  訪問密碼 e4b8

最終總結

不管是同一應用中還是不同應用之間,standard、singleTop、singleInstance各自沒有區別,只有singleTask不一樣,同一應用中不創建新的task,不同應用中有可能會創建新的task。(注:這里用到了“可能”二字,沒有用“一定”,是因為這與taskAffinity屬性有關,如果設置了此屬性,就會在該屬性對應的task中啟動實例,否則,會創建新的task)。

轉自:feeyan


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM