Activity啟動模式

TheSpectier發表於2024-09-10

Activity啟動模式

1. Activity啟動模式介紹

1.1 任務棧

在Android開發中,任務棧(Task Stack)是一個非常重要的概念,主要用於管理應用程式中的Activity及其啟動模式。它幫助開發者瞭解當使用者在不同應用之間切換,或者應用內部不同Activity之間跳轉時,系統如何管理這些Activity的生命週期與顯示行為。任務棧是一個後進先出(LIFO, Last In First Out)的堆疊結構,用來存放應用程式啟動的Activity。當使用者啟動一個新的Activity時,系統會將其壓入任務棧頂部,使用者可以透過返回按鈕(back)將棧頂的Activity彈出(銷燬),顯示當前棧頂的Activity。系統中可以存在多個任務棧,當前所在任務棧的棧頂Activity例項會被顯示。

1.2 啟動模式分類

在Android開發中,啟動模式(Launch Mode)是指系統在管理Activity時如何處理該Activity的啟動和任務棧的行為。它決定了一個Activity在被啟動時是否建立新的例項、如何與已有的任務棧互動,以及在應用導航中如何管理Activity的狀態。當你啟動一個Activity時,系統需要決定是否建立一個新的Activity例項,或者複用已經存在的例項,這些行為是由啟動模式控制的。其中standard模式、singleTop模式和singleInstancePerTask模式都是針對當前任務棧的;singleTask和singleInstance模式是針對系統全域性的。啟動模式的設定分為靜態設定動態設定兩種。

1.2.1 standard

standard(標準模式)是Activity預設的啟動模式,即當前Activity未顯式設定啟動模式情況下,其啟動模式為standard。在standard模式下,每次啟動該Activity系統都會建立一個新的例項(instance)並壓入當前任務棧頂,不論是否已有相同Activity例項存在。Activity例項數量沒有限制,具體取決於任務棧深度。該模式適用於大多數情景,例如在一個應用中開啟多個頁面。其模式原理如下圖。

1.2.2 singleTop

當Activity啟動模式設定為singleTop時,系統啟動該Activity時若發現當前任務棧棧頂(並非系統全域性)為該Activity例項,則會直接複用該例項(呼叫onNewIntent()方法)而不會重新建立;若當前任務棧棧頂不為該Activity例項時,則會建立新的例項無論當前或其他任務棧中是否已存在對應例項。該模式適用於在同一任務中頻繁跳轉回當前頁面的場景,例如從通知點選進入訊息頁面。其模式原理圖如下。

1.2.3 singleTask

當Activity啟動模式設定為singleTask時,系統啟動該Activity時若發現存在一個任務棧(系統全域性)中存在該Activity例項時,則會直接複用該例項(呼叫onNewIntent()方法)而不會重新建立,同時將該任務棧中位於該例項之上的其它Activity例項都將會被彈出棧,該例項作為當前任務棧棧頂;若所有任務棧中都不存在該Activity例項時,則會在當前任務棧中建立該Activity例項作為棧頂。該例項在所有任務棧中唯一存在。該模式適用於“主頁”類Activity,或者需要保證該Activity在整個應用中只有一個例項的場景,如應用的主介面、設定介面。其模式原理圖如下。

1.2.4 singleInstance

當Activity啟動模式設定為singleInstance時,系統全域性只允許存在該Activity的一個例項,並且該Activity將獨佔一個任務棧。系統啟動該Activity時,若所有任務棧中都不存在該Activity例項時,系統會使用一個獨立的任務棧,並在該棧中建立該Activity例項,該任務棧只用於管理該Activity例項,唯一存在;當該Activity例項已經存在於獨立的任務棧中時,系統會直接複用該例項,該例項在所有任務棧中唯一存在。該模式適用於鎖屏頁面、影片播放等需要獨立管理的Activity,防止干擾。其模式原理圖如下。

1.2.5 singleInstancePerTask

singleInstancePerTask 是 Android API 31(即 Android 12)引入的一種新的啟動模式。這種模式可以看作是對 singleInstance 和 singleTask 啟動模式的一種補充,目的是增強應用在多工場景中的靈活性。當Activity啟動模式設定為singleInstancePerTask時,系統啟動該Activity時若發現當前任務棧中存在該Activity例項時,則會直接複用該例項;若不存在,則在當前任務棧中建立新的例項作為棧頂。該模式適用於需要跨多個任務棧獨立執行,但每個任務棧中只允許一個例項的 Activity,如多視窗操作中,每個視窗都需要獨立的 Activity 例項。

2. 靜態設定啟動模式

2.1 透過AndroidManifest.xml中的launchMode屬性

靜態設定是指在AndroidManifest.xml檔案中,透過在標籤中新增android:launchMode屬性來指定Activity的啟動模式。這種方式在應用安裝時就已經固定,不會在執行時發生變化。示例如下:

點選檢視程式碼
<activity android:name=".MainActivity"
          android:launchMode="singleTop">
</activity>

2.2 靜態設定特點

  • 編譯時確定:在編譯時指定,執行時無法更改。
  • 全域性適用:對於該Activity的所有啟動方式,都會按照指定的啟動模式處理。
  • 可讀性高:在Manifest檔案中一目瞭然,有助於維護。

3. 動態設定啟動模式

3.1 透過Intent的Flags屬性

動態設定是指在程式碼中,透過為Intent新增特定的Flag(標誌)來指定Activity的啟動行為。這些Flag會影響Activity的啟動模式和任務棧的管理。示例如下:

點選檢視程式碼
#kotlin
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(intent)

3.2 常用Flag介紹

  • FLAG_ACTIVITY_NEW_TASK:這個標誌會告訴系統為新啟動的 Activity 建立一個新的任務棧(Task),如果該 Activity 已經存在於某個棧中,它將複用現有的任務棧並將 Activity 新增到棧頂。該標誌在啟動一個新的 Activity 時是強制性的,特別是在從非 Activity 上下文(如 Service 或 BroadcastReceiver)啟動 Activity 時。
  • FLAG_ACTIVITY_SINGLE_TOP:如果啟動的 Activity 已經在棧頂,則複用它的例項,而不是建立新的例項。如果該 Activity 不在棧頂,系統將建立一個新的例項並將其推到棧頂。這個標誌類似於在 launchMode 中設定 singleTop。
  • FLAG_ACTIVITY_CLEAR_TOP:當啟動的 Activity 已經存在於任務棧中時,它會清除這個 Activity 之上的所有其他 Activity。然後,系統會將這個 Activity 置於棧頂並複用它的例項。這通常與 FLAG_ACTIVITY_NEW_TASK 結合使用。
  • FLAG_ACTIVITY_CLEAR_TASK:這個標誌會清除目標 Activity 所在的整個任務棧(Task)。所有位於該任務棧中的 Activity 都會被銷燬,然後啟動目標 Activity 作為新的棧根。
  • FLAG_ACTIVITY_REORDER_TO_FRONT:如果目標 Activity 已經在任務棧中,但不是棧頂,系統會將它移動到棧頂,而不銷燬棧中的其他 Activity,也不會建立新的例項。
  • FLAG_ACTIVITY_NO_HISTORY:該標誌表示啟動的 Activity 不會被新增到任務棧中,也就是說當使用者離開這個 Activity 後,系統將不會儲存它的狀態。這常用於啟動短暫的頁面,如登入頁面、廣告頁面等。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:這個標誌會防止啟動的 Activity 出現在“最近任務”(Recents)中。即使使用者透過多工按鈕檢視任務列表,該 Activity 也不會出現在列表中。

3.3 onNewIntent() 方法

當使用動態設定的Flags複用已經存在的Activity時,系統不會呼叫onCreate()方法,因為沒有建立新的例項。相反,系統會呼叫onNewIntent()方法。你可以在onNewIntent()方法中處理傳遞給Activity的新的Intent。

點選檢視程式碼
#Kotlin
override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    // 處理新Intent
}

3.4 動態設定特點

  • 靈活性高:動態設定允許根據應用執行時的不同場景靈活控制Activity的啟動行為。例如,你可以在接收到不同的Intent時,根據使用者操作動態決定是否複用現有的Activity例項或清理任務棧。
  • 更精細的控制:透過組合多個Flags,動態設定可以提供比靜態設定更為細緻的行為控制,滿足複雜的應用需求。

4. 總結

在實際開發中,可以結合靜態和動態設定。例如,為某些核心頁面設定靜態啟動模式,同時在程式碼中根據業務邏輯使用Intent Flags動態調整特定場景下的啟動行為。

相關文章