任務(wù)棧
- android任務(wù)棧又稱為Task谴返,它是一個棧結(jié)構(gòu)赖晶,具有后進(jìn)先出的特性巾兆,用于存放我們的Activity組件如捅。
- 我們每次打開一個新的Activity或者退出當(dāng)前Activity都會在一個稱為任務(wù)棧的結(jié)構(gòu)中添加或者減少一個Activity組件同欠,因此一個任務(wù)棧包含了一個activity的集合, android系統(tǒng)可以通過Task有序地管理每個activity样傍,并決定哪個Activity與用戶進(jìn)行交互:只有在任務(wù)棧棧頂?shù)腶ctivity才可以跟用戶進(jìn)行交互。
- 在我們退出應(yīng)用程序時铺遂,必須把所有的任務(wù)棧中所有的activity清除出棧時,任務(wù)棧才會被銷毀衫哥。當(dāng)然任務(wù)棧也可以移動到后臺, 并且保留了每一個activity的狀態(tài). 可以有序的給用戶列出它們的任務(wù), 同時也不會丟失Activity的狀態(tài)信息。
- 需要注意的是襟锐,一個App中可能不止一個任務(wù)棧撤逢,某些特殊情況下,單獨一個Actvity可以獨享一個任務(wù)棧粮坞。還有一點就是一個Task中的Actvity可以來自不同的App蚊荣,同一個App的Activity也可能不在一個Task中。
任務(wù)棧信息可以通過 adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p'
指令來查看 棧信息.
四種啟動模式
-
standard
: 默認(rèn)的啟動模式,每次啟動一個Activity都會重新創(chuàng)建一個新的實例,不管這個實例是否存在.Activity的啟動三回調(diào)(onCreate()->onStart()->onResume())都會執(zhí)行莫杈。 如在一個任務(wù)棧中,連續(xù)調(diào)用3次MainActivity
,那么任務(wù)占中就會存在三個MainActivity
記錄. -
singTop
: 棧頂復(fù)用模式. 當(dāng)準(zhǔn)備啟動的Activity已經(jīng)位于任務(wù)棧棧頂時,不會再創(chuàng)建一個新的Activity,此時棧頂Activity的onNewIntent
方法會被回調(diào).當(dāng)準(zhǔn)備啟動的Activity不在任務(wù)棧的棧頂存在時,(無論在棧中存在或者在非棧頂),都會重新創(chuàng)建 Activity. -
singleInstance
: 單實例模式. 系統(tǒng)為聲明為singleInstance
模式的Activity,單獨使用一個任務(wù)棧存放.即一個Activity對應(yīng)一個任務(wù)棧,且一個Activity最多存在一個實例. 后續(xù)請求都不會創(chuàng)建Activity,只會調(diào)用其onNewIntent
回調(diào). -
singleTask
: 棧內(nèi)復(fù)用模式. 在這種模式下,如果Activity已經(jīng)存在某個任務(wù)棧中,多起啟動該Activity都不會被重建,只會調(diào)用其onNewIntent
方法,并將其移動到棧頂位置.
singleTask
模式
當(dāng)啟動Activity時,如果Activity已經(jīng)存在于 任務(wù)棧的非棧頂位置, 任務(wù)棧中該Activity之上的 Activity將會被全部移除,只保留該Activity以及其一下的Activity.
即 具有 clearTop
的效果.
當(dāng)啟動Activity的任務(wù)棧B在后臺時,此時任務(wù)棧A中的Activity啟動了,任務(wù)棧B中的 singleTask
模式的Activity,則任務(wù)B棧的 被啟動Activity會clearTop
到棧頂位置,然后整個任務(wù)棧B重返至前臺.
引用 官方示例來說明 :
前臺棧中的棧頂Activity2 啟動了 位于后臺棧的 ActivityY,此時 后臺棧中的 ActivityY和ActivityX 都會被移動至前臺棧中,回退兩次才能回到 Activity2.
taskAffinity
屬性
taskAffinity
是AndroidManifest
中 Activity標(biāo)簽的屬性,表示任務(wù)棧的名稱.該屬性可以為 Activity指定任務(wù)棧.
當(dāng)Activity的啟動模式為
standard,singletop
模式時,taskAffinity
屬性將失效, Activity的將被加入到 啟動它的那個Activity所在的棧.一個例外,如果在入口Activity中指定taskAffinity
屬性,則可以生效,因為此時應(yīng)用剛啟動,還沒有指定的任務(wù)棧(默認(rèn)的任務(wù)棧是以包名來命名的).當(dāng)Activity的啟動模式為
singleTask,singleInstance
模式時,taskAffinity
屬性將在Activity被啟動的時候指定任務(wù)棧,如果任務(wù)棧不存在則會創(chuàng)建一個taskAffinity
命名的任務(wù)棧存放啟動的Activity.
注意事項
如果被啟動的Activity是
standard,singletop
模式時, Activity將被加入到啟動該Activity的任務(wù)棧中.如果被啟動的Activity是
singleTask,singleInstance
模式時,如果指定taskAffinity
屬性,則Activity被加入到 指定的棧任務(wù)棧中,未指定則被加入 以包名命名的任務(wù)棧.singleInstance
模式的Activity,雖然可能被加入到名字相同的棧,但是由于其特殊性,雖然棧名相同但是不屬于同一個棧.使用 application來啟動Activity時, application沒有所在的 任務(wù)棧.如果沒有指定
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
-
FLAG_ACTIVITY_NEW_TASK
: 為Activity指定singleTask
模式,相當(dāng)于在xml中指定啟動模式一樣,除了application來啟動Activity時,在xml指定singleTask
是無效的,一定要在intent中指定該標(biāo)志. -
FLAG_ACTIVITY_SINGLE_TOP
: 指定singleTop
模式. -
FLAG_ACTIVITY_CLEAR_TOP
: 具有此標(biāo)記的Activity,當(dāng)它啟東市,在同一個任務(wù)棧中的所有位于它上面的Activity都將被移除任務(wù)棧. -
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
: 設(shè)置了該標(biāo)志,該Activity所在的任務(wù)棧將不會出現(xiàn)在 多任務(wù)列表(最近使用列表)中.相當(dāng)于設(shè)置了android:excludeFromRecents="true"
.
IntentFilter匹配規(guī)則
intent的啟動有兩種方式,顯式調(diào)用和隱式調(diào)用.
顯示調(diào)用,我們需要明確的指定被啟動的Activity的組件信息,Activity的class對象.
隱式調(diào)用則不需要明確的知道 被調(diào)用的Activity信息,而是通過IntentFilter
來指定action,category,data
過濾規(guī)則配合來啟動Activity.
Intent只有同時匹配了 action
規(guī)則,category
規(guī)則 和 data
規(guī)則,才能成功的啟動目標(biāo)Activity.
一個 IntentFilter
中可以設(shè)置多個 action
,多個category
和多個data
.
action
intent中必須設(shè)置 action
, 且能過匹配 IntentFilter
中的任意一個 action
就算匹配成功.
category
intent中如果含有 category
,那么所有的category
都能在IntentFilter
中匹配上,intent中也可以不顯式的設(shè)置category
.
在調(diào)用 startActivity
或者startActivityForResult
時,系統(tǒng)會為intent自動添加 android.intent.category.DEFAULT
標(biāo)志,所以如果要想隱式的調(diào)用Activity,就必須在 IntentFilter
中添加 <category android:name="android.intent.category.DEFAULT" />
規(guī)則.
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結(jié)構(gòu) : <scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>]
mimeType : image/jpeg
,video/*
等.
如果IntentFilter
中設(shè)置了 data
屬性.則intent中必須設(shè)置 setData
或者setType
或者setDataAndType
.
setData
或者setType
方法的屬性會相互覆蓋.各自的方法會將對方屬性設(shè)置為null
.
當(dāng)data
中指設(shè)置了 mimeType
時,可以使用 scheme
為 file或content
類型來設(shè)置data
.
如果需要同時指定URI
和mimeType
,需要使用intent的setDataAndType
方法.
隱式調(diào)用,可達(dá)性檢查
隱式intent啟動之前,我們可以先檢查 目標(biāo)Activity的可達(dá)性,避免出現(xiàn) android.content.ActivityNotFoundException: No Activity found to handle Intent
的錯誤.
使用 intent的 intent.resolveActivity(packageManager)
和 packageManager的packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)
來檢查, 返回 null
則表示找不到匹配的Activity.