任務棧
- android任務棧又稱為Task,它是一個棧結構,具有後進先出的特性,用于存放我們的Activity元件。
- 我們每次打開一個新的Activity或者退出目前Activity都會在一個稱為任務棧的結構中添加或者減少一個Activity元件,是以一個任務棧包含了一個activity的集合, android系統可以通過Task有序地管理每個activity,并決定哪個Activity與使用者進行互動:隻有在任務棧棧頂的activity才可以跟使用者進行互動。
- 在我們退出應用程式時,必須把所有的任務棧中所有的activity清除出棧時,任務棧才會被銷毀。當然任務棧也可以移動到背景, 并且保留了每一個activity的狀态. 可以有序的給使用者列出它們的任務, 同時也不會丢失Activity的狀态資訊。
- 需要注意的是,一個App中可能不止一個任務棧,某些特殊情況下,單獨一個Actvity可以獨享一個任務棧。還有一點就是一個Task中的Actvity可以來自不同的App,同一個App的Activity也可能不在一個Task中。
任務棧資訊可以通過
adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p'
指令來檢視 棧資訊.
四種啟動模式
-
: 預設的啟動模式,每次啟動一個Activity都會重新建立一個新的執行個體,不管這個執行個體是否存在.Activity的啟動三回調(onCreate()->onStart()->onResume())都會執行。 如在一個任務棧中,連續調用3次standard
,那麼任務占中就會存在三個MainActivity
記錄.MainActivity
-
: 棧頂複用模式. 當準備啟動的Activity已經位于任務棧棧頂時,不會再建立一個新的Activity,此時棧頂Activity的singTop
方法會被回調.當準備啟動的Activity不在任務棧的棧頂存在時,(無論在棧中存在或者在非棧頂),都會重新建立 Activity.onNewIntent
-
: 單執行個體模式. 系統為聲明為singleInstance
模式的Activity,單獨使用一個任務棧存放.即一個Activity對應一個任務棧,且一個Activity最多存在一個執行個體. 後續請求都不會建立Activity,隻會調用其singleInstance
回調.onNewIntent
-
: 棧内複用模式. 在這種模式下,如果Activity已經存在某個任務棧中,多起啟動該Activity都不會被重建,隻會調用其singleTask
方法,并将其移動到棧頂位置.onNewIntent
singleTask
模式
singleTask
當啟動Activity時,如果Activity已經存在于 任務棧的非棧頂位置, 任務棧中該Activity之上的 Activity将會被全部移除,隻保留該Activity以及其一下的Activity.
即 具有
clearTop
的效果.
當啟動Activity的任務棧B在背景時,此時任務棧A中的Activity啟動了,任務棧B中的
singleTask
模式的Activity,則任務B棧的 被啟動Activity會
clearTop
到棧頂位置,然後整個任務棧B重返至前台.
引用 官方示例來說明 :

2018-10-02-22-46-05
前台棧中的棧頂Activity2 啟動了 位于背景棧的 ActivityY,此時 背景棧中的 ActivityY和ActivityX 都會被移動至前台棧中,回退兩次才能回到 Activity2.
taskAffinity
屬性
taskAffinity
taskAffinity
是
AndroidManifest
中 Activity标簽的屬性,表示任務棧的名稱.該屬性可以為 Activity指定任務棧.
- 當Activity的啟動模式為
模式時,standard,singletop
屬性将失效, Activity的将被加入到 啟動它的那個Activity所在的棧.一個例外,如果在入口Activity中指定taskAffinity
屬性,則可以生效,因為此時應用剛啟動,還沒有指定的任務棧(預設的任務棧是以包名來命名的).taskAffinity
-
singleTask,singleInstance
屬性将在Activity被啟動的時候指定任務棧,如果任務棧不存在則會建立一個taskAffinity
命名的任務棧存放啟動的Activity.taskAffinity
注意事項
- 如果被啟動的Activity是
模式時, Activity将被加入到啟動該Activity的任務棧中.standard,singletop
-
模式時,如果指定singleTask,singleInstance
屬性,則Activity被加入到 指定的棧任務棧中,未指定則被加入 以包名命名的任務棧.taskAffinity
模式的Activity,雖然可能被加入到名字相同的棧,但是由于其特殊性,雖然棧名相同但是不屬于同一個棧.singleInstance
- 使用 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
-
: 為Activity指定FLAG_ACTIVITY_NEW_TASK
模式,相當于在xml中指定啟動模式一樣,除了application來啟動Activity時,在xml指定singleTask
是無效的,一定要在intent中指定該标志.singleTask
-
: 指定FLAG_ACTIVITY_SINGLE_TOP
模式.singleTop
-
: 具有此标記的Activity,當它啟東市,在同一個任務棧中的所有位于它上面的Activity都将被移除任務棧.FLAG_ACTIVITY_CLEAR_TOP
-
: 設定了該标志,該Activity所在的任務棧将不會出現在 多任務清單(最近使用清單)中.相當于設定了FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
.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.