天天看點

Activity的啟動模式

任務棧

  1. android任務棧又稱為Task,它是一個棧結構,具有後進先出的特性,用于存放我們的Activity元件。
  2. 我們每次打開一個新的Activity或者退出目前Activity都會在一個稱為任務棧的結構中添加或者減少一個Activity元件,是以一個任務棧包含了一個activity的集合, android系統可以通過Task有序地管理每個activity,并決定哪個Activity與使用者進行互動:隻有在任務棧棧頂的activity才可以跟使用者進行互動。
  3. 在我們退出應用程式時,必須把所有的任務棧中所有的activity清除出棧時,任務棧才會被銷毀。當然任務棧也可以移動到背景, 并且保留了每一個activity的狀态. 可以有序的給使用者列出它們的任務, 同時也不會丢失Activity的狀态資訊。
  4. 需要注意的是,一個App中可能不止一個任務棧,某些特殊情況下,單獨一個Actvity可以獨享一個任務棧。還有一點就是一個Task中的Actvity可以來自不同的App,同一個App的Activity也可能不在一個Task中。

任務棧資訊可以通過

adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p'

指令來檢視 棧資訊.

四種啟動模式

  1. standard

    : 預設的啟動模式,每次啟動一個Activity都會重新建立一個新的執行個體,不管這個執行個體是否存在.Activity的啟動三回調(onCreate()->onStart()->onResume())都會執行。 如在一個任務棧中,連續調用3次

    MainActivity

    ,那麼任務占中就會存在三個

    MainActivity

    記錄.
  2. singTop

    : 棧頂複用模式. 當準備啟動的Activity已經位于任務棧棧頂時,不會再建立一個新的Activity,此時棧頂Activity的

    onNewIntent

    方法會被回調.當準備啟動的Activity不在任務棧的棧頂存在時,(無論在棧中存在或者在非棧頂),都會重新建立 Activity.
  3. singleInstance

    : 單執行個體模式. 系統為聲明為

    singleInstance

    模式的Activity,單獨使用一個任務棧存放.即一個Activity對應一個任務棧,且一個Activity最多存在一個執行個體. 後續請求都不會建立Activity,隻會調用其

    onNewIntent

    回調.
  4. singleTask

    : 棧内複用模式. 在這種模式下,如果Activity已經存在某個任務棧中,多起啟動該Activity都不會被重建,隻會調用其

    onNewIntent

    方法,并将其移動到棧頂位置.

singleTask

模式

當啟動Activity時,如果Activity已經存在于 任務棧的非棧頂位置, 任務棧中該Activity之上的 Activity将會被全部移除,隻保留該Activity以及其一下的Activity.

即 具有

clearTop

的效果.

當啟動Activity的任務棧B在背景時,此時任務棧A中的Activity啟動了,任務棧B中的

singleTask

模式的Activity,則任務B棧的 被啟動Activity會

clearTop

到棧頂位置,然後整個任務棧B重返至前台.

引用 官方示例來說明 :

Activity的啟動模式

2018-10-02-22-46-05

前台棧中的棧頂Activity2 啟動了 位于背景棧的 ActivityY,此時 背景棧中的 ActivityY和ActivityX 都會被移動至前台棧中,回退兩次才能回到 Activity2.

taskAffinity

屬性

taskAffinity

AndroidManifest

中 Activity标簽的屬性,表示任務棧的名稱.該屬性可以為 Activity指定任務棧.

  1. 當Activity的啟動模式為

    standard,singletop

    模式時,

    taskAffinity

    屬性将失效, Activity的将被加入到 啟動它的那個Activity所在的棧.一個例外,如果在入口Activity中指定

    taskAffinity

    屬性,則可以生效,因為此時應用剛啟動,還沒有指定的任務棧(預設的任務棧是以包名來命名的).
  2. singleTask,singleInstance

    taskAffinity

    屬性将在Activity被啟動的時候指定任務棧,如果任務棧不存在則會建立一個

    taskAffinity

    命名的任務棧存放啟動的Activity.

注意事項

  1. 如果被啟動的Activity是

    standard,singletop

    模式時, Activity将被加入到啟動該Activity的任務棧中.
  2. singleTask,singleInstance

    模式時,如果指定

    taskAffinity

    屬性,則Activity被加入到 指定的棧任務棧中,未指定則被加入 以包名命名的任務棧.

    singleInstance

    模式的Activity,雖然可能被加入到名字相同的棧,但是由于其特殊性,雖然棧名相同但是不屬于同一個棧.
  3. 使用 application來啟動Activity時, application沒有所在的 任務棧.如果沒有指定

    FLAG_ACTIVITY_NEW_TASK

    ,将會有如下報錯.
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
           

Activity中的 Flags

  1. FLAG_ACTIVITY_NEW_TASK

    : 為Activity指定

    singleTask

    模式,相當于在xml中指定啟動模式一樣,除了application來啟動Activity時,在xml指定

    singleTask

    是無效的,一定要在intent中指定該标志.
  2. FLAG_ACTIVITY_SINGLE_TOP

    : 指定

    singleTop

    模式.
  3. FLAG_ACTIVITY_CLEAR_TOP

    : 具有此标記的Activity,當它啟東市,在同一個任務棧中的所有位于它上面的Activity都将被移除任務棧.
  4. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

    : 設定了該标志,該Activity所在的任務棧将不會出現在 多任務清單(最近使用清單)中.相當于設定了

    android:excludeFromRecents="true"

    .

IntentFilter比對規則

intent的啟動有兩種方式,顯式調用和隐式調用.

顯示調用,我們需要明确的指定被啟動的Activity的元件資訊,Activity的class對象.

隐式調用則不需要明确的知道 被調用的Activity資訊,而是通過

IntentFilter

來指定

action,category,data

過濾規則配合來啟動Activity.

Intent隻有同時比對了

action

規則,

category

規則 和

data

規則,才能成功的啟動目标Activity.

一個

IntentFilter

中可以設定多個

action

,多個

category

和多個

data

action

intent中必須設定

action

, 且能過比對

IntentFilter

中的任意一個

action

就算比對成功.

category

intent中如果含有

category

,那麼所有的

category

都能在

IntentFilter

中比對上,intent中也可以不顯式的設定

category

在調用

startActivity

或者

startActivityForResult

時,系統會為intent自動添加

android.intent.category.DEFAULT

标志,是以如果要想隐式的調用Activity,就必須在

IntentFilter

中添加

<category android:name="android.intent.category.DEFAULT" />

規則.

data

<data android:scheme="string"
      android:host="string"
      android:port="string"
      android:path="string"
      android:pathPattern="string"
      android:pathPrefix="string"
      android:mimeType="string" />
           

data由兩部分組成, URI 和 mimeType(媒體類型).

URI結構 :

<scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>]

mimeType :

image/jpeg

,

video/*

等.

如果

IntentFilter

中設定了

data

屬性.則intent中必須設定

setData

setType

setDataAndType

setData

setType

方法的屬性會互相覆寫.各自的方法會将對方屬性設定為

null

data

中指設定了

mimeType

時,可以使用

scheme

file或content

類型來設定

data

如果需要同時指定

URI

mimeType

,需要使用intent的

setDataAndType

方法.

隐式調用,可達性檢查

隐式intent啟動之前,我們可以先檢查 目标Activity的可達性,避免出現

android.content.ActivityNotFoundException: No Activity found to handle Intent

的錯誤.

使用 intent的

intent.resolveActivity(packageManager)

和 packageManager的

packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)

來檢查, 傳回

null

則表示找不到比對的Activity.

參考

  1. Android開發藝術探索(任玉剛)
  2. 任務和傳回棧(android官方教程)
下一篇: Java 集合