一、AndroidManifest.xml
中指定launchMode
1.1standard
標準模式,每次啟動Activity
都會建立一個新的Activity
例項,並且將其壓入任務棧棧頂,而不管這個 Activity 是否已經存在,都會執行onCreate() ->onStart() -> onResume
。
1.2 singleTop
棧頂複用模式,如果新Activity
已經位於棧頂,那麼此Activity
不會被重新建立,同時Activity
的 onNewIntent
方法會被回撥,如果Activity
已經存在但是不再棧頂,那麼和standard
模式一樣。
如果Activity
當前是onResume
狀態,那麼呼叫後會執行onPause() -> onNewIntent() -> onResume()
。
1.3 singleTask
棧內複用模式,建立這樣的Activity
,系統會確認它所需任務棧是否已經建立,否則先建立任務棧,然後放入Activity
,如果棧中已經有一個Activity
例項,那麼會做兩件事:
- 這個
Activity
會回到棧頂執行onNewIntent
- 清理在當前
Activity
上面的所有Activity
上面的如果棧中已經有一個Activity
例項,這個判斷條件的**標準是由android:taskAffinity
**決定的,下面我們做一個簡單的對比:
- 第一種情況,不給
singleTask
的Activity
設定taskAffinity
,這時預設情況下屬於同一個Application
的所有Activity
具有的taskAffinity
是相同的,就是我們在AndroidManifest
中指定的packageName
:
<activity android:name=".SingleTaskActivity" android:launchMode="singleTask"/>
複製程式碼
這時候我們從MainActivity
啟動SingleTaskActivity
後,任務棧的情況是,MainActivity
和 SingleTaskActivity
處於同一個Task
當中:
SingleTaskActivity
和MainActivity
位於同一個棧中,因此singleTask
並不是讓這個Activity
獨佔一個Task
。
- 第二種情況,給
singleTask
的Activity
設定affinity
:
<activity android:name=".SingleTaskActivity" android:launchMode="singleTask" android:taskAffinity="com.android.singleTask"/>
複製程式碼
此時進行同樣的操作,任務棧的情況變為:
我們在SingleTaskActivity
的介面按下 Home
鍵,再點選圖示進入MainActivity
,可以看到當前應用有兩個棧:
此時,我們再點選按鈕啟動SingleTaskActivity
,那麼會執行
MainActivity#onPause
SingleTaskActivity#onNewIntent
SingleTaskActivity#onRestart
SingleTaskActivity#onStart
SingleTaskActivity#onResume
MainActivity#onStop
複製程式碼
這是由於當啟動SingleTaskActivity
,系統去尋找該SingleTaskActivity
所對應的棧是否存在,而這時候是存在的,也就上面看到TaskRecord[cd9ca5d]
,所以它不會建立新的SingleTaskActivity
,而是複用這個棧中的Activity
,而由於這個Activity
又位於棧頂,因此它的表現和SingleTop
相同。
- 第三種情況,我們試著在第二種的基礎上再加大一些難度, 在
SingleTaskActivity
所在的Task
上再加一個SingleTaskAboveActivity
,首先我們從MainAcitivity -> SingleTaskActivity -> SingleTaskAboveActvity
<activity android:name=".SingleTaskAboveActivity"/>
複製程式碼
這一流程過後,棧的結構為,可以看到SingleTaskActivity
和SingleTaskAboveActvity
位於同一棧中:
SingleTaskAboveActvity
介面,按Home
退到後臺之後重新進入,棧的結構不變,只不過當前可見的是 MainActivity
,這時我們再次嘗試啟動SingleTaskActivity
,那麼會依次呼叫:
MainActivity#onPause
SingleTaskAboveActivity#onDestroy
SingleTaskActivity#onNewIntent
SingleTaskActivity#onRestart
SingleTaskActivity#onStart
SingleTaskActivity#onResume
MainActivity#onStop
複製程式碼
而棧的結構變為如下:
和第二種情況類似,當啟動SingleTaskActivity
時,系統去尋找該SingleTaskActivity
所對應的棧是否存在,而這時候是存在的,也就上面看到TaskRecord[a3771ca]
,所以它不會建立新的SingleTaskActivity
,而是複用這個棧中的SingleTaskActivity
,但此時SingleTaskActivity
並不位於棧頂,在它上面還有一個SingleTaskAboveActivity
,因此會把SingleTaskAboveActivity
先出棧,再複用原先位於這個棧中的SingleTaskActivity
例項。
1.4 singleInstance
這種模式的Activity
只能單獨位於一個任務棧內,由於棧內的複用特性,後續請求均不會建立新的Activity
,除非這個獨特的任務棧被系統銷燬了。
- 第一種情況,先看最簡單的,我們新建一個
SingleInstanceActivity
<activity android:name=".SingleInstanceActivity" android:launchMode="singleInstance"/>
複製程式碼
我們從MainAcitivity
啟動它,此時任務棧的情況是,他們位於不同的Task
中,符合我們的預期:
- 第二種情況,此時按
Home
回到桌面,再重新點圖示進入MainActivity
,任務棧依然是兩個,我們此時再啟動SingleInstanceActivity
:
MainActivity#onPause
SingleInstanceActivity#onNewIntent
SingleInstanceActivity#onRestart
SingleInstanceActivity#onStart
SingleInstanceActivity#onResume
MainActivity#onStop
複製程式碼
和啟動在另一個棧中已存在的singleTaskAcitivity
的情況是類似的。
- 第三種情況,我們再看一下,
affinity
對於singleInstance
會不會有影響呢,我們定義兩個affinity
相同的singleInstance
:
<activity android:name=".SingleInstanceActivity" android:launchMode="singleInstance" android:taskAffinity="com.android.singleInstance"/>
<activity android:name=".SingleInstanceActivityAnother" android:launchMode="singleInstance" android:taskAffinity="com.android.singleInstance"/>
複製程式碼
我們先從MainActivity
啟動SingleInstanceActivity
,按Home
回到桌面再進入,此時Task
的情況和上面相同的,那麼這時候我們啟動SingleInstanceActivityAnother
:
affinity
的影響,而是重新起了一個新的棧。
二、在Intent
當中指定啟動模式
2.1 FLAG_ACTIVITY_NEW_TASK
和singleTask
行為相同,前面已經詳細分析過了,這裡需要注意 affinity 的宣告。
2.2 FLAG_ACTIVITY_SINGLE_TOP
和singleTop
行為相同,比較簡單,就不舉例子了。
2.3 FLAG_ACTIVITY_CLEAR_TASK
和 FLAG_ACTIVITY_NEW_TASK
何用,這個Activity
會新起一個棧,原來棧被清空,棧中的Activity
也被銷燬。
2.5 FLAG_ACTIVITY_CLEAR_TOP
會清除這個Activity
之上所有的Activity
,我們來試一下,新建兩個新的SecondActivity
和ThirdActivity
,從Main -> Second -> Third
,此時棧的結構是:
SecondActivity
:
public void third(View view) {
Intent intent = new Intent(this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
複製程式碼
這之後,棧的結構變為,ThirdAcitivity
被出棧了:
2.6 FLAG_ACTIVITY_REORDER_TO_FRONT
上面的FLAG_ACTIVITY_CLEAR_TOP
是把位於目標Activity
之上的Activity
都銷燬,而則個FLAG
則是對棧重新排序,把目標Activity
移到最前臺,其它的位置不變,我們在前一種的基礎上,在ThirdActivity
中換一種方式來啟動SecondActivity
:
public void third(View view) {
Intent intent = new Intent(this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
複製程式碼
這回,最終棧的結構變為了,可以看到ThirdActivity
並沒有被出棧:
三、AndroidManifest
中的屬性
3.1 alwaysRetainTaskState
這個標誌只對根Activity
有用,預設情況下,當我們的應用在後臺一段時間,它會銷燬該Task
除了根以外的所有Activity
,如果我們希望保持這個Task
的原有狀態,那麼給這個Task
的根Activity
設定這個屬性,預設值是false
。
3.2 clearTaskOnLaunch
從桌面啟動該Activity
的時候會清空該Task
除了根Activity
外的所有Activity
,我們從Main -> Second -> Third
,此時棧內有3個Activity
,按Home
回到桌面後,點圖示重新進入,此時Task
只剩下根Activity
了:
3.3 finishOnTaskLaunch
這個和上面類似,但是它對根Activity
無效,我們給SecondActivity
設定這個屬性,先啟動到ThirdActivity
,這時候棧的結構為:
接著,我們按Home
回到桌面,點圖示重新進入,棧的結構變為下面這樣,可以看到SecondActivity
沒有了:
3.4 noHistory
Activity
在不可見之後,不儲存記錄
- 第一種情況,我們給
SecondActivity
設定這個屬性,接著從Main -> Second -> Third
,然後按Back
返回,此時的生命週期為:
ThirdActivity#onPause
MainActivity#onRestart
MainActivity#onStart
MainActivity#onResume
SecondActivity#onDestroy
ThirdActivity#onStop
ThirdActivity#onDestroy
複製程式碼
- 第二種情況,如果我們在
ThirdActivity
時,不是按Back
,而是按Home
到桌面,會呼叫:
ThirdActivity#onPause
SecondActivity#onDestroy
ThirdActivity#onStop
複製程式碼
- 第三種情況,我們給根
MainAcitivity
設定這個屬性,啟動它後退出:
MainActivity#onCreate
MainActivity#onStart
MainActivity#onResume
MainActivity#onDestory
複製程式碼