1. 程式人生 > >Android四大元件之Activity-啟動模式

Android四大元件之Activity-啟動模式

1.Activity的啟動模式

當我們多次呼叫同一個Activity時,系統會重複建立多個例項並把它們一一放入任務棧中,這種方式顯然不符合我們的設計要求。所以Android在設計時就提供了四種啟動模式來解決此問題。

四種啟動模式分別如下:

  1. standard-標準模式也是預設模式 每次啟動一個Activity都會建立新的例項並壓入任務棧,onCreate,onStart,onResume都會被呼叫。每個任務棧可以有多個例項,每個例項也可屬於不同的任務棧。例如: A->B,B為standard模式,B即屬於A的任務棧。 A B C D 再次啟動A(standard模式)
當前任務棧存在的元素 啟動後的任務棧存在的元素
A B C D A B C D A
  1. singleTop-棧頂複用模式 此模式下,比如新的Activity已經位於棧頂,那麼此Activity不會被重新建立,會回撥它的onNewIntent方法,它的onCreate,onStart不會被系統呼叫。如果新的Activity不是位於棧頂,那麼它還是會被重新建立。例: A B C D 再次啟動D(singleTop模式) A B D C 再次啟動D(singleTop模式)
當前任務棧存在的元素 啟動後的任務棧存在的元素
A B C D A B C D
A B D D A B D C D
  1. singleTask-棧內複用模式 單例項模式,只要Activity在一個棧中存在,多次啟動都不會重新建立例項,系統會回撥onNewIntent方法。 如果要啟動一個啟動模式為singleTask的Activity A,先判斷是否存在A所需的任務棧,不存在->新建立任務棧並把例項A壓入。如果存在,判斷A是否在棧中存在例項,存在移到棧頂,並將之前的例項出棧,如果不存在例項,建立並壓入棧。
任務棧S1存在A B C,啟動D(singleTask模式)(所需任務棧S2),因為S2與D例項均不存在,所以系統會新建任務棧S2並建立D壓入S2。
任務棧S1存在A B C,啟動D(singleTask模式)(所需任務棧S1),啟動D後的S1為A B C D。
任務棧S1存在A D B C,啟動D(singleTask模式)(所需任務棧S1),啟動D後的S1為A D。

使用:

<activity
            android:name=".MainActivity"
            android:configChanges="orientation|screenSize"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
</activity>

 override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        Log.d(TAG, "--onNewIntent--")
    }

在這裡插入圖片描述

可以看出MainActivity始終沒有被重新建立

  1. singleInstance-單例項模式 加強的singleTask模式,擁有singleTask的所有特點且只能單獨的位於一個任務棧中。

特殊情況

?:現在有S1-前臺任務棧,S2-後臺任務棧(singleTask模式)。S1有A B,S2有C D。
現在啟動D,S2整個任務棧會切換至S1中,即S1存在 A B C D,依此按下返回鍵例項一一出棧。
現在啟動C,S2整個任務棧會切換至S1中,即S1存在 A B C,依此按下返回鍵例項一一出棧。

2.任務棧

前面所說的Activity所需任務棧是什麼?即TaskAffinity引數:這個引數標識了一個Activity所需任務棧的包名。此屬性主要與singleTask啟動模式或者allowReparenting屬性配對使用。

1.當與singleTask配對使用時,啟動的Activity會執行在名字與TaskAffinity相同的任務棧中。
2.當與allowReparenting配對使用時,情況比較特殊。
現有應用A與B(存在Activity C),現在A啟動B的C,點選Home鍵。點選B 會啟動C。--C從A的任務棧轉移到了B的任務棧。

簡單使用: A為standrad B為singleTask TaskAffinity值為”com.wdl.test“。模擬過程A->B->A

    <activity
            android:name=".MainActivity"
            android:configChanges="orientation|screenSize"
            android:launchMode="standard">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".Main2Activity"
            android:taskAffinity="com.wdl.test"
            android:launchMode="singleTask"/>

控制檯輸入adb shell dumpsys activity

在這裡插入圖片描述

發現此時存在兩個任務棧 一個為包含B A的S1(com.wdl.test),另一個為只有A的S2 (com.wdl.kt1)

分為2類:

  • 前臺任務棧
  • 後臺任務棧,位於暫停狀態

3.如何給Activity指定啟動模式

  1. 通過AndroidMenifest.xml為Activity指定啟動模式
  <activity android:name=".Main2Activity"
            android:launchMode="singleTask"/>
  1. 在Intent中設定標誌位為Activity指定啟動模式
  val intent = Intent(this,MainActivity::class.java)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            startActivity(intent)

常用的標誌位有:

作用
FLAG_ACTIVITY_NEW_TASK 指定singleTask啟動模式
FLAG_ACTIVITY_SINGLE_TOP 指定singleTop啟動模式
FLAG_ACTIVITY_CLEAR_TOP 此Activity(singleTask)之前的例項全部要出棧; Activity(standard)之前與本身的例項全部要出棧,重新建立例項併入棧
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 具有此標記的Activity不會出現在歷史Activity中

二者的區別: 1.優先順序上第二種方式高於第一種方式。 2.限定範圍上有所不同 例:第一種方式無法直接為Activity設定FLAG_ACTIVITY_CLEAR_TOP標識;第二種方式無法為Activity指定singleInstance模式