Activity啓動模式及任務棧

前言

在默認情況下,每當我們啓動一個Activity,Android系統都會爲我們創建一個新的實例並將其加入任務棧中。如果多次啓動同一個Activity,任務棧就會存在多個相同的實例。這樣做顯然是不夠高效的,因此Android爲Activity提供了多種啓動模式。在具體的場景下選用合適的啓動模式,可以大大提高應用性能。

Activity啓動模式

standard

標準模式。這是Activity默認的啓動模式,每次啓動Activity都會生成一個新的實例。通過這種方式啓動的Activity實例,默認會被添加到啓動它的Activity所在的任務棧中。

singleTop

棧頂複用模式。如果被啓動的Activity實例已經位於任務棧棧頂,則不會再創建新的實例,該Activity的onNewIntent方法將被調用。否則,依舊會創建新的Activity實例。

singleTask

棧內複用模式。如果被啓動的Activity實例已經存在於任務棧內,則不會創建新的實例。Android系統將會把該Activity實例之上的其它Activity出棧,然後回調這個Activity的onNewIntent方法。需要注意的是,如果在AndroidManifest中爲被啓動的Activity指定了獨有的taskAffinity屬性,則Activity將會在指定的的任務棧中創建。如果這個任務棧不存在,則會先創建這個任務棧。具體細節請參考後文任務棧部分。

singleInstance

單實例模式。這是一種加強型的singleTask模式。這種啓動模式不僅擁有singleTask的所有特性,還確保Activity實例將會在一個獨有的任務棧創建。換句話說,指定了這種啓動模式的Activity實例將獨享一個任務棧。只要在這個任務棧中存在該Activity的實例,後續啓動這個Activity就不會創建新的實例了,只會調用它的onNewIntent方法。否則,Android系統會先創建任務棧,然後在該任務棧中創建這個Activity的實例。

任務棧

任務棧是一種“先進後出”的數據結構,負責存儲Activity的實例。默認情況下,所有Activity的任務棧名都和它的應用包名相同。但是,我們可以通過在AndroidManifest文件中爲Activity指定taskAffinity屬性,爲Activity指定其他的任務棧名。如下所示:

  <activity
        android:name=".MainActivity"
          android:taskAffinity="com.codingending.newtask">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
  </activity>

需要注意,taskAffinity不能指定爲應用包名,否則相當於沒有指定。此外,這個字符串中需要出現包名分隔符.。一般這個屬性會配合singleTask啓動模式一起使用。任務棧可以存在多個,因而會分爲前臺任務棧後臺任務棧。後臺任務棧中的Activity都處於暫停狀態。通過啓動後臺任務棧中的Activity,可以將後臺任務棧切換到前臺。

如何爲Activity指定啓動模式

有兩種方式可以爲Activity指定啓動模式。一種是直接在AndroidManifest文件中爲Activity指定launchMode屬性。如下所示,就爲Activity指定了singleTask啓動模式:

<activity
        android:name=".MainActivity"
        android:launchMode="singleTask">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>

另一種是在代碼中爲Intent添加flags標誌位指定啓動模式。如下所示,就通過singleTask模式啓動了Activity:

Intent intent=new Intent(MainActivity.this,ViewActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

這兩種啓動模式都可以很方便地爲Activity指定啓動模式,但是也存在部分區別。從優先級來看,第二種方式優先於第一種方式。從指定範圍來看,也存在少數不同。例如,第一種方式無法直接設置FLAG_ACTIVITY_CLEAR_TOP標誌位,而第二種方式則無法直接指定singleInstance啓動模式。

Activity中常見的標誌位

Intent.FLAG_ACTIVITY_NEW_TASK

對應singleTask啓動模式。

Intent.FLAG_ACTIVITY_SINGLE_TOP

對應singleTop啓動模式。

Intent.FLAG_ACTIVITY_CLEAR_TOP

這個標誌位一般和singleTask配合使用,實際上singleTask默認就包含了這一標誌位。它的作用是將任務棧中被啓動Activity實例之上的所有Activity實例出棧。如果被啓動Activity的啓動模式是singleTask,則它的onNewIntent方法將被調用。需要注意的是,如果被啓動Activity的啓動模式是standard,則任務棧內該Activity實例及其以上的Activity都會出棧,然後Android系統會創建一個新的Activity實例加入棧內。

Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

這個標誌位的作用是將Activity從最近啓動的列表中移除,在特殊情況下有用,對應AndroidManifest文件中的excludeFromRecents屬性。如下所示:

<activity
        android:name=".MainActivity"
        android:excludeFromRecents="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>
發佈了49 篇原創文章 · 獲贊 77 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章