Android activity四種啟動模式及taskAffinity屬性總結(附例子原始碼)
Android activity四種啟動模式總結
本人目前在看 Android 開發藝術探索 這本書,書中對啟動模式的講解比較詳細,所以自己想總結下。
如果各位能認真的看上一遍,相信會對android activity的啟動模式會有更加深刻的印象。
Android啟動模式:launchMode在多個Activity跳轉的過程中扮演著非常重要的作用,它可以決定是否生成新的activity例項,是否重用已存在的activity例項,是否和其他的activity例項公用一個task(任務棧)。
task(任務棧)的概念:task是一個具有棧結構的物件,一個task可以管理多個activity例項,啟動一個應用,也就建立一個與之對應的task。task裡面的activity是按照先進後出的形式儲存的。比如:你開啟一個頁面,在頁面中開啟另一個頁面,另一個頁面退出後,返回的是第一個開啟的頁面。這就是任務棧的簡單原理。
棧頂的概念:只要是頁面剛開啟,不管他是什麼模式的,它都是棧頂頁面。
棧低的概念:首先開啟的頁面位於最底下,然後後面開啟的頁面依次往上堆。只有最底下的頁面關閉,程式才算完成關閉。
啟動模式的概念及理解:
1、standard (標準啟動模式):是預設的啟動模式,不用為其配置android:launchMode屬性即可。在這種模式下啟動的activity可以被多次例項化,即在同一個task中可以存在多個activity的例項。每次啟動standard模式的activity時,都建立activity例項並放入task。
比如:Activity A的啟動模式為standard,並且A已經啟動,在A中再次啟動Activity A,即呼叫startActivity(new Intent(this, A.class)),會在A的上面再次啟動一個A的例項,即當前的task中狀態為A-->A。
2、singleTop(棧頂複用模式):需要為其配置android:launchMode = "singleTop"。如果一個以singleTop模式啟動的activity的例項已經存在於task的棧頂,那麼再次啟動這個activity時,不會建立新的例項,而是重用位於棧頂的那個例項,並且會呼叫該例項的inNewIntent()方法將Intent物件傳遞到這個例項中。
比如:如果A的啟動模式為singleTop,並且A的一個例項已經存在於棧頂中,那麼再呼叫startActivity(new Intent(this, A.class))啟動A時,不會再次建立A的例項,而是重用原來的例項,並且呼叫原來例項的onNewIntent()方法。這時任務棧中還是隻有一個A的例項。
注意:如果以singleTop模式啟動的acitivity的一個例項已經存在與task中,但是不在棧頂,那麼它的行為和standard模式相同,也會建立多個例項。
3、singleTask(棧內複用模式):需要為其配置android:launchMode="singleTask"。如果要啟動的Activity(singleTask模式)在task(任務棧)中存在該例項,則不需要建立,只需要把次activity放入棧頂,並把該activity以上的activity例項都移出棧裡面;如果不存在該例項就建立該例項放在棧頂。也就是說:一個棧裡面只能有一個singleTask模式的activity。
比如:(1)singleTask模式的activity已經存在棧頂,那麼跳轉到自己的頁面,它是不會建立自己的activity例項物件的,這個和SingleTop是一樣的。 但如果singleTask模式的Activity已經不在棧頂,那麼跳轉到自己的頁面,它是不會建立自己的activity例項的,而是會直接跳轉到自己的例項activity,並且把壓在該模式之上的所有activity例項都移除棧,但是該模式底下的activity例項它是沒有辦法移除的。
(2)如果singleTask模式的activity都還沒有建立,那麼它會建立它的activity例項物件,並把自己放在棧頂,這個和所有的activity例項物件都是一樣的。
注意:一般app主頁面都是用SingleTask模式來設計,因為使用者點選多次頁面的相互跳轉後,再點選回到主頁,再次點選退出,這時他的實際需求就是要退出程式,而不是一次一次關閉剛才跳轉過的頁面,最後才退出。
4、singleInstance(全域性唯一模式):需要配置android:launchMode="singleInstance"。該模式下,無論是從哪個任務棧中啟動activity,只會建立一個目標的activity例項,並且使用一個全新的task棧來載入該activity例項。 可以看出SingleInstance模式比SingleTask模式更加霸道,開啟一個SingleTask模式的activity,它如果已經存在,它會把在它之上的該task中的所有activity例項移除。而開啟SingleInstance模式的activity,不管它存不存在,它都會新建一個task,把自己放在裡面,也就是說剛開啟的SingleInstance的activity在自己新建的task中只有自己一個例項物件。
該模式具備singleTask模式的所有特性外,與它的區別就是,這種模式下的Activity會單獨佔用一個Task棧,具有全域性唯一性,即整個系統中就這麼一個例項,由於棧內複用的特性,後續的請求均不會建立新的Activity例項,除非這個特殊的任務棧被銷燬了。以singleInstance模式啟動的Activity在整個系統中是單例的,如果在啟動這樣的Activiyt時,已經存在了一個例項,那麼會把它所在的任務排程到前臺,重用這個例項。
SingleInstance模式一般用於資源的共享。比如使用QQ開啟軟體A和軟體B。發現退出QQ程式後,原來開啟的程式並沒有被關閉。
我們可以在AndroidManifest.xml配置的android:launchMode屬性為以上四種之一即可。如圖所示:
舉例如下:
注意:那個activity啟動另一個activity,那麼被啟動的activity就會在啟動的activity所在的棧.
例如:
1.Activity A 要啟動Activity B,那麼Activity B就會在Activity所在的棧中,並且,Activity B是在Activity A的上面.
現在有兩個棧
棧A:有A,B,C 三個標準啟動模式的activity
棧B:有D,E 兩個singleTask啟動模式的activity
這個使用,Activity C要啟動Activity E,那麼啟動之後,棧A中的元素順序就是:Activity A,Activity B,Activity C,Activity D,Activity E;
這個時候,點選物理返回鍵返回後,顯示的Activity 是Activity D
如果Activity C要啟動的是Activity D,啟動後,棧A的元素順序就是:Activity A,Activity B,Activity C,Activity D.
這個時候,點選物理返回按鍵返回後,顯示的就是Activity C;
taskAffinity屬性:
那麼什麼是taskAffinity屬性呢,可以簡單的理解為任務相關性。
- 這個引數標識了一個Activity所需任務棧的名字,預設情況下,所有Activity所需的任務棧的名字為應用的包名
- 我們可以單獨指定每一個Activity的taskAffinity屬性覆蓋預設值
- 一個任務的affinity決定於這個任務的根activity(root activity)的taskAffinity
- 在概念上,具有相同的affinity的activity(即設定了相同taskAffinity屬性的activity)屬於同一個任務
- 為一個activity的taskAffinity設定一個空字串,表明這個activity不屬於任何task
很重要的一點taskAffinity屬性不對standard和singleTop模式有任何影響,即時你指定了該屬性為其他不同的值,這兩種啟動模式下不會建立新的task(如果不指定即預設值,即包名)
(1)standard和singleTop啟動模式都是在原任務棧中新建Activity例項,不會啟動新的Task,即使你指定了taskAffinity屬性。
(2)singleTask啟動模式啟動Activity時,首先會根據taskAffinity去尋找當前是否存在一個對應名字的任務棧
- 如果不存在,則會建立一個新的Task,並建立新的Activity例項入棧到新建立的Task中去
- 如果存在,則得到該任務棧,查詢該任務棧中是否存在該Activity例項
如果存在例項,則將它上面的Activity例項都出棧,然後回撥啟動的Activity例項的onNewIntent方法
如果不存在該例項,則新建Activity,併入棧
此外,我們可以將兩個不同App中的Activity設定為相同的taskAffinity,這樣雖然在不同的應用中,但是Activity會被分配到同一個Task中去。
總結的不好之處 望各位大神給予指正
測試程式碼傳送門:https://github.com/1066893961/LaunchModeTest.git