Activity 知識梳理(2) Activity 棧

1、AndroidManifest.xml中指定launchMode

1.1standard

標準模式,每次啓動Activity都會建立一個新的Activity實例,而且將其壓入任務棧棧頂,而無論這個 Activity 是否已經存在,都會執行onCreate() ->onStart() -> onResumeandroid

1.2 singleTop

棧頂複用模式,若是新Activity已經位於棧頂,那麼此Activity不會被從新建立,同時ActivityonNewIntent方法會被回調,若是Activity已經存在可是再也不棧頂,那麼和standard模式同樣。 若是Activity當前是onResume狀態,那麼調用後會執行onPause() -> onNewIntent() -> onResume()bash

1.3 singleTask

棧內複用模式,建立這樣的Activity,系統會確認它所需任務棧是否已經建立,不然先建立任務棧,而後放入Activity若是棧中已經有一個Activity實例,那麼會作兩件事:this

  • 這個Activity會回到棧頂執行onNewIntent
  • 清理在當前Activity上面的全部Activity

上面的若是棧中已經有一個Activity實例,這個判斷條件的**標準是由android:taskAffinity**決定的,下面咱們作一個簡單的對比:spa

  • 第一種狀況,不給singleTaskActivity設置taskAffinity,這時默認狀況下屬於同一個Application的全部Activity具備的taskAffinity是相同的,就是咱們在AndroidManifest中指定的packageName
<activity android:name=".SingleTaskActivity" android:launchMode="singleTask"/>
複製代碼

這時候咱們從MainActivity啓動SingleTaskActivity後,任務棧的狀況是,MainActivitySingleTaskActivity處於同一個Task當中: code

咱們看到 SingleTaskActivityMainActivity位於同一個棧中,所以 singleTask並非讓這個 Activity獨佔一個 Task

  • 第二種狀況,給singleTaskActivity設置affinity
<activity android:name=".SingleTaskActivity" android:launchMode="singleTask" android:taskAffinity="com.android.singleTask"/>
複製代碼

此時進行一樣的操做,任務棧的狀況變爲: xml

咱們在 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"/>
複製代碼

這一流程事後,棧的結構爲,能夠看到SingleTaskActivitySingleTaskAboveActvity位於同一棧中:生命週期

SingleTaskAboveActvity界面,按 Home退到後臺以後從新進入,棧的結構不變,只不過當前可見的是 MainActivity,這時咱們再次嘗試啓動 SingleTaskActivity,那麼會依次調用:

MainActivity#onPause
SingleTaskAboveActivity#onDestroy
SingleTaskActivity#onNewIntent
SingleTaskActivity#onRestart
SingleTaskActivity#onStart
SingleTaskActivity#onResume
MainActivity#onStop
複製代碼

而棧的結構變爲以下: ip

和第二種狀況相似,當啓動 SingleTaskActivity時,系統去尋找該 SingleTaskActivity所對應的棧是否存在,而這時候是存在的,也就上面看到 TaskRecord[a3771ca],因此它不會建立新的 SingleTaskActivity,而是複用這個棧中的 SingleTaskActivity,但此時 SingleTaskActivity並不位於棧頂,在它上面還有一個 SingleTaskAboveActivity,所以會把 SingleTaskAboveActivity先出棧,再複用原先位於這個棧中的 SingleTaskActivity實例。

1.4 singleInstance

這種模式的Activity只能單獨位於一個任務棧內,因爲棧內的複用特性,後續請求均不會建立新的Activity,除非這個獨特的任務棧被系統銷燬了。ci

  • 第一種狀況,先看最簡單的,咱們新建一個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

singleInstance_another.png
能夠看到,它並無受到 affinity的影響,而是從新起了一個新的棧。

2、在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,咱們來試一下,新建兩個新的SecondActivityThirdActivity,從Main -> Second -> Third,此時棧的結構是:

clearTop_1.png
此時,咱們按以下方式啓動 SecondActivity

public void third(View view) {
        Intent intent = new Intent(this, SecondActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);
    }
複製代碼

這以後,棧的結構變爲,ThirdAcitivity被出棧了:

clearTop_2.png

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並無被出棧:

Paste_Image.png

3、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 了:

Paste_Image.png

3.3 finishOnTaskLaunch

這個和上面相似,可是它對根Activity無效,咱們給SecondActivity設置這個屬性,先啓動到ThirdActivity,這時候棧的結構爲:

Paste_Image.png

接着,咱們按Home回到桌面,點圖標從新進入,棧的結構變爲下面這樣,能夠看到SecondActivity沒有了:

Paste_Image.png

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
複製代碼
相關文章
相關標籤/搜索