//如下Activity中,launchmode如其名: HomeActivity -->
// StandardActivity -->
// singleTaskActivity -->
// singleInstanceActivity -->
// standardActivity -->
// CameraActivity(調用系統相機方法)
// adb shell dumpsys activity
Stack #1:
Task id #5
TaskRecord{7546973 #5 A=com.e_gavin163.listest U=0 sz=5}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.e_gavin163.listest/.task_test.HomeActivity }
Hist #4: ActivityRecord{700d91d u0 com.android.camera/.CameraActivity t5}
Intent { act=android.media.action.IMAGE_CAPTURE cmp=com.android.camera/.CameraActivity }
ProcessRecord{d91c03e 25810:com.android.camera/u0a81}
Hist #3: ActivityRecord{e341be0 u0 com.e_gavin163.listest/.task_test.StandardActity t5}
Intent { flg=0x10400000 cmp=com.e_gavin163.listest/.task_test.StandardActity }
ProcessRecord{79171f5 26358:com.e_gavin163.listest/u0a110}
Hist #2: ActivityRecord{faf6cf1 u0 com.e_gavin163.listest/.task_test.SingleTaskActivity t5}
Intent { flg=0x10000000 cmp=com.e_gavin163.listest/.task_test.SingleTaskActivity }
ProcessRecord{79171f5 26358:com.e_gavin163.listest/u0a110}
Hist #1: ActivityRecord{a4a7fb9 u0 com.e_gavin163.listest/.task_test.StandardActity t5}
Intent { cmp=com.e_gavin163.listest/.task_test.StandardActity }
ProcessRecord{79171f5 26358:com.e_gavin163.listest/u0a110}
Hist #0: ActivityRecord{9e21af3 u0 com.e_gavin163.listest/.task_test.HomeActivity t5}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.e_gavin163.listest/.task_test.HomeActivity }
ProcessRecord{79171f5 26358:com.e_gavin163.listest/u0a110}
Task id #6
TaskRecord{db084a9 #6 A=com.e_gavin163.listest U=0 sz=1}
Intent { flg=0x10000000 cmp=com.e_gavin163.listest/.task_test.SingleInstanceActivity }
Hist #0: ActivityRecord{fac5462 u0 com.e_gavin163.listest/.task_test.SingleInstanceActivity t6}
Intent { flg=0x10000000 cmp=com.e_gavin163.listest/.task_test.SingleInstanceActivity }
ProcessRecord{79171f5 26358:com.e_gavin163.listest/u0a110}
Running activities (most recent first):
TaskRecord{7546973 #5 A=com.e_gavin163.listest U=0 sz=5}
Run #5: ActivityRecord{700d91d u0 com.android.camera/.CameraActivity t5}
Run #4: ActivityRecord{e341be0 u0 com.e_gavin163.listest/.task_test.StandardActity t5}
TaskRecord{db084a9 #6 A=com.e_gavin163.listest U=0 sz=1}
Run #3: ActivityRecord{fac5462 u0 com.e_gavin163.listest/.task_test.SingleInstanceActivity t6}
TaskRecord{7546973 #5 A=com.e_gavin163.listest U=0 sz=5}
Run #2: ActivityRecord{faf6cf1 u0 com.e_gavin163.listest/.task_test.SingleTaskActivity t5}
Run #1: ActivityRecord{a4a7fb9 u0 com.e_gavin163.listest/.task_test.StandardActity t5}
Run #0: ActivityRecord{9e21af3 u0 com.e_gavin163.listest/.task_test.HomeActivity t5}
mResumedActivity: ActivityRecord{700d91d u0 com.android.camera/.CameraActivity t5}
Stack #0:
.
.
.
個人總結:
- 一個應用程序只有一個任務棧
(Stack)
; - 一個應用程序可以有多個
Task
(一個Task
表現于回退棧,按返回鍵可以推出最上面的Activity
) - 只有
SingleInstance
會新建一個Task
,而不在當前回退棧里面;在SingleInstance
模式的Activity
里面startActivity
,新建的Activity
的TaskID
也是之前主Task
的ID
,而不會是SingleInstance
的TaskID
,SingleInstance
獨占一個TaskID
. - 在當前
Activity
中調用其他應用的ActivityB
,ActivityB
會添加到當前應用程序的棧中,并且和當前Activity
同TaskID
(AcitivytB
的launchMode
不為SingleInstance
情況下)。但是不同process
,ActivityB
只會跑在自己的process
中。
以下內容轉自franksunny
很想弄清楚啟動一個Activity
和Task
(任務)的關系,網上也有很多相關資料,由從源碼來具體分析的,也有針對launchmode
來分析,但都不是自己的,理解起來總不是那么容易,為此,嘗試著自己去理解其中的邏輯。不過事先需要弄清楚兩個問題:
誰負責管理Activity?
Android
的framework
框架中采用C/S
的方式實現由后臺服務ActivityManagerService
(很多書上將其簡稱為Ams
)來管理具體的Acitivity
實例,雖然Ams
命名為ActivityManagerService
,但是它其實不僅僅管理Activity
,他還管理除Acitvity
外的其它三大組件,還包括Intent
、pendingintent
、apk
進程和task
等等,具體可以查看源碼frameworks\base\services\java\com\android\server\am
下面的Ams
源碼和相關的*Record
類。
??網上資料顯示在2.3以后的SDK中,Ams
將原來的HistoryRecord
類重新命名為ActivityRecord
類,并將其原來Ams
中的一些處理抽出來成為一個ActivityStack
類,每一個Activity
實例對應一個ActivityRecord
對象,并存放在ActivityStack
中,手機一旦啟動,就會啟動一個Ams服務,在Ams
服務中有一個ActivityStack
實例專門管理手機上的ActivityRecord
實例。這樣一來,不具體分析源碼,僅從架構角度來說誰負責管理Activity的問題就清晰多了。
Task到底是什么?
根據對上面問題的解答,既然Activity
是由Ams
通過ActivityStack
來管理的,那么這個Task
又是干什么的呢?
??以往基于應用(application)
的程序開發中,程序具有明確的邊界,一個程序就是一個應用,一個應用為了實現功能可以采用開辟新線程甚至新進程來輔助,但是應用與應用之間不能復用資源和功能。而Android
引入了基于組件開發的軟件架構,雖然我們開發android
程序,仍然使用一個apk
工程一個Application
的開發形式,但是對于Aplication的開發就用到了Activity
、service
等四大組件,其中的每一個組件,都是可以被跨應用復用的哦,這個就是android
的神奇之處。
??另外值得一提的是,雖然組件可以跨應用被調用,但是一個組件所在的進程必須是在組件所在的Aplication
進程中。由于android
強化了組件概念,弱化了Aplication
的概念,所以在android
程序開發中,A應用的A組件想要使用拍照或錄像的功能就可以不用去針對Camera
類進行開發,直接調用系統自帶的攝像頭應用(稱其B應用)中的組件(稱其B組件)就可以了,但是這就引發了一個新問題,A組件跑在A應用中,B組件跑在B應用中,自然都不在同一個進程中,那么從B組件中返回的時候,如何實現正確返回到A組件呢?Task
就是來負責實現這個功能的,它是從用戶角度來理解應用而建立的一個抽象概念。因為用戶所能看到的組件就是Activity
,所以Task可以理解為實現一個功能而負責管理所有用到的Activity
實例的棧。
??其實查看源碼,在Ams
內部,并不是真的有這么一個存放Activity
的Task
棧,Activity
還是通過ActivityStack
來管理,在ActivityRecord
中有一個TaskRecord
對象記錄了真實的Activity
實例是屬于哪個Task
的。Task
通過一個int
類型的TaskId
來唯一標識,該值在手機重啟時將會被置零。
??說了這么多,還是找一個Task
任務最直觀的體現吧。先重啟手機,長按home
鍵,發現彈出的最近任務中一個任務也沒有,然后開啟A應用,長按home
鍵,會發現有一個A應用的任務,查看手機進程,應該還沒有B進程的;在A應用的A組件中調B應用的B組件,此時看手機的進程,除了A進程外,還有個B的進程,但是長按home鍵,能看到的還是只有一個A應用的任務。其實這個時候,B應用已經跑起來了,但是對用戶來說,他其實沒有開啟過B應用,所以Task任務自始至終都是從用戶的角度出發而設計的概念,保證用戶的調用邏輯。
Activity、Application與進程的關系
理清楚了上述兩個概念問題,進入Activity
的啟動與Task
的關系之前,讓我們先來了解下啟動一個Activity
與apk Application
和進程的關系。對Activity
啟動過程具體的分析,工程耗時很龐大,網上有個老羅整理的三篇博客,我看了半天還是云里霧里的。我通過我現在的認識和目前通過Demo
的測試來看,啟動一個Activity
時,Ams
首先會去查詢該Activity
所在的應用是否開啟,如果沒有開啟則會啟動一個進程去Run
這個Application
,因此無論通過Launcher
還是通過常規的程序內部調用startActivity
來啟動一個Activity
,所要啟動的Activity
都是跑在其注冊的apk
所在的Application
進程中(或者該組件android:process
指定的進程中),而其TaskID
一般是和啟動它的組件所屬的TaskId
一致,但是也不盡然,這就要看下面的具體分析了。
??另外通過對service
的應用,可以得出結論,一個apk
,即一個應用(Application)
可以跑在多個進程中,一個進程在一個虛擬機中運行,也即一個apk
可以啟動多個虛擬機。
??通過shareuserID
可以將多個apk
,跑在同一個進程中。
??從而得出結論:一個虛擬機只能跑一個進程,一個進程里可以跑多個應用,一個應用也可以跑在多個進程中,這就是他們的關系。
Activity和Task的關系
啟動一個Activity
有兩種方式,一種就是通過Launcher
,另外一種是通過程序代碼調用startActivity
函數實現(驗證過AppWidget
其實與這種方式是一致的)其實影響Activity
啟動關鍵點大致有三個因素:Activity
注冊信息中的launchMode
、啟動Activity
時Intent
中的launchFlags
和Activity
注冊信息中的taskAffinity、allowTaskReparenting
、clearTaskOnLaunch
、alwaysRetainTaskState
、finishOnTaskLaunch
等信息。通常情況下,我們只需要針對第一個因素進行合理設置就能滿足我們應用開發的需求了。
??launchMode
的四種方式
??launchMode
方法是在apk
的manifest
文件中針對每一個Activity
的android:launchMode
屬性進行設置的方式,共有四種模式可以設置,分別是standard、singleTop、singleTask、singleInstance
,下面分別闡述之(由于其中幾種因素有設置時,會影響lauchMode
的四種模式,所以下面情況下,其它因素都是缺省不設置的情況)。
standard
standard
是默認模式,即假設用戶在manifest
中對Activity
不指定android:launchMode
的情況下,缺省啟動模式即為standard。在啟動一個以standard
為launchMode
的Activity
時,Ams
只是簡單的創建一個新的Activity
實例,將其放到ActivityStack
(為了行文方便,后面將ActivityStack
簡稱AS
),其TaskId
則與啟動這個Activity
的調用者Activity
相同(即就算創建一個新的進程,但是其TaskId
還是跟調用者一致的,以確保用戶回退操作時保持一致)。這種是最常見的使用方式。
singleTop
啟動一個以singleTop
為lauchMode
的Activity
時,Ams
會查詢AS
:假如在AS
頂端正是要啟動的Activity
實例,那么Ams
就不會重新啟動一個Activity
實例,而是調用AS
棧頂的該Activity
實例的OnNewIntent
函數(自然不會修改原來的TaskId值);假如在AS
棧頂不是該Activity
的實例,那么就會創建一個新的實例,將其壓入AS
,其TaskId
與調用者Activity
相同。這種方式主要用于避免自調自過程中,產生多個實例的情況。
singleTask
啟動一個以singleTask
為lauchMode
的Activity
時,Ams
會查詢AS
:如果AS
內有一個該類Activity
的實例,那么就會將該實例置于TS
的頂端(原來位于該實例上面的其它同TaskId
的activity
實例,將被銷毀),并調用該實例的onNewIntent
函數;如果AS
內沒有該類的實例,就會啟動一個新的實例,將其壓入AS
,其TaskID
與啟動它的調用者沒有必然關系,而是取決于該Activity
所在apk
進程是否有TaskId
,假如沒有就會創建一個新的TaskId
。在實測中發現,如果singleTask
模式啟動的Activity
是AS
中同TaskId
的最底部一個(或被稱謂Task
棧的根實例),那么在通過桌面長按,在近期任務中跳轉到Activity所在的任務時,即使該Activity
實例不是在棧頂,也會被置到棧頂(還會調用其onNewIntent
函數),并將AS
上同TaskId
的其它Activity
實例銷毀,具體可以通過附帶的demo來驗證,其中TaskOne
中的Activity1
置成singleTask
啟動模式,其它均為默認的standard
,其log
輸出如下:
//在TaskTwo中啟動Activity1,此前TaskOne apk沒有在運行,所以啟動Activity1時會申請一個新的TaskId,2afcfbd8這個Activity1成為了TaskId為53的Task棧棧底實例
04-05 16:21:27.144: E/ActivityB @2b003230(17933): onPause pid 17933 taskid 52
04-05 16:21:27.404: E/Activity1 @2afcfbd8(18489): onCreate pid 18489 taskid 53
04-05 16:21:29.214: E/ActivityB @2afecaf0(17933): onCreate pid 17933 taskid 53
04-05 16:21:30.254: E/Activity2 @2afdeef0(18489): onCreate pid 18489 taskid 53
04-05 16:21:30.894: E/ActivityB @2aff9328(17933): onCreate pid 17933 taskid 53
04-05 16:21:31.454: E/Activity2 @2afe9330(18489): onCreate pid 18489 taskid 53
04-05 16:21:31.864: E/ActivityB @2b009910(17933): onCreate pid 17933 taskid 53
04-05 16:21:32.424: E/Activity2 @2aff2570(18489): onCreate pid 18489 taskid 53
//通過長按跳轉到TaskOne任務,此時在AS中id為53的在Activity1上面有6個
04-05 16:22:35.144: E/ActivityB @2afecaf0(17933): onDestroy pid 17933 taskid 53
04-05 16:22:35.144: E/Activity2 @2afdeef0(18489): onDestroy pid 18489 taskid 53
04-05 16:22:35.234: E/ActivityB @2aff9328(17933): onDestroy pid 17933 taskid 53
04-05 16:22:35.254: E/Activity2 @2afe9330(18489): onDestroy pid 18489 taskid 53
04-05 16:22:35.324: E/ActivityB @2b009910(17933): onDestroy pid 17933 taskid 53
04-05 16:22:35.344: E/Activity2 @2aff2570(18489): onPause pid 18489 taskid 53
04-05 16:22:35.394: E/Activity1 @2afcfbd8(18489): onNewIntent pid 18489 taskid 53
04-05 16:22:35.394: E/Activity1 @2afcfbd8(18489): onStart pid 18489 taskid 53
04-05 16:22:35.394: E/Activity1 @2afcfbd8(18489): onResume pid 18489 taskid 53
04-05 16:22:35.524: E/Activity2 @2aff2570(18489): onStop pid 18489 taskid 53
04-05 16:22:35.524: E/Activity2 @2aff2570(18489): onDestroy pid 18489 taskid 53
singleInstance
啟動一個以singleInstance
為launchmode
的Activity
時,假如AS
中已經有一個該類實例,那么調用其onNewIntent
函數;否則就會創建一個新的TaskId
,與該Activity
所在的apk
進程完全不同的TaskId
,而且這個TaskId
值以后也不會被用于其他任何Activity
實例中。
簡單小結
一般我們開發普通的應用程序時,我們只需要使用缺省的standard
和singleTop
方式就夠用了,不需要使用singleTask
和singleInstance
來聲明注冊的Activity
,因為它將破壞用戶感覺上的回退操作,給用戶使用上帶來迷惑,所以一般將這兩者用于很耗資源的Activity
,通過查看源碼發現在源碼packages\apps
中的程序,有如下一些應用使用了這兩者高級設置
AndroidManifest.xml (packages\apps\browser): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\calendar): <activity android:name="AlertActivity" android:launchMode="singleInstance"
AndroidManifest.xml (packages\apps\contacts): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\deskclock): android:launchMode="singleInstance"
AndroidManifest.xml (packages\apps\deskclock): android:launchMode="singleInstance"
AndroidManifest.xml (packages\apps\deskclock): android:launchMode="singleInstance"
AndroidManifest.xml (packages\apps\email): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\launcher2): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\music): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\phone): android:launchMode="singleInstance"
AndroidManifest.xml (packages\apps\phone): android:launchMode="singleInstance">
AndroidManifest.xml (packages\apps\quicksearchbox): android:launchMode="singleTask"
AndroidManifest.xml (packages\apps\settings): android:launchMode="singleTask"
AndroidManifest.xml (packages\providers\downloadprovider): android:launchMode="singleTask"
在上述分析中沒有將其它兩個因素引入,主要是自己在這方面接觸的也比較少,而且這三方面因素共同組合會產生很多種不同效果,所以就沒做具體展開。轉載一些網友收集的資料如下:
跟Task有關的manifest文件中Activity的特性值介紹
android:allowTaskReparenting
用來標記Activity
能否從啟動的Task
移動到有著affinity
的Task
(當這個Task
進入到前臺時)
??“true”
,表示能移動,“false”
,表示它必須呆在啟動時呆在的那個Task
里。
??如果這個特性沒有被設定,設定到<application>
元素上的allowTaskReparenting
特性的值會應用到Activity
上。默認值為“false”
。
??一般來說,當Activity
啟動后,它就與啟動它的Task
關聯,并且在那里耗盡它的整個生命周期。當當前的Task
不再顯示時,你可以使用這個特性來強制Activity
移動到有著affinity
的Task
中。典型用法是:把一個應用程序的Activity
移到另一個應用程序的主Task
中。
??例如,如果 email
中包含一個web
頁的鏈接,點擊它就會啟動一個Activity
來顯示這個頁面。這個Activity
是由Browser
應用程序定義的,但是,現在它作為email Task
的一部分。如果它重新宿主到Browser Task
里,當Browser
下一次進入到前臺時,它就能被看見,并且,當email Task
再次進入前臺時,就看不到它了。
??Actvity
的affinity
是由taskAffinity
特性定義的。Task
的affinity
是通過讀取根Activity
的affinity
決定。因此,根Activity
總是位于相同affinity
的Task
里。由于啟動模式為“singleTask”
和“singleInstance”
的Activity
只能位于Task
的底部,因此,重新宿主只能限于“standard”
和“singleTop”
模式。
android:alwaysRetainTaskState
用來標記Activity
所在的Task
的狀態是否總是由系統來保持。
??“true”
,表示總是;“false”
,表示在某種情形下允許系統恢復Task
到它的初始化狀態。默認值是“false”
。
??這個特性只針對Task
的根Activity
有意義;對其它Activity
來說,忽略之。
??一般來說,特定的情形如當用戶從主畫面重新選擇這個Task
時,系統會對這個Task
進行清理(從stack
中刪除位于根Activity
之上的所有Activivity
)。典型的情況,當用戶有一段時間沒有訪問這個Task
時也會這么做,例如30分鐘。
??然而,當這個特性設為“true”
時,用戶總是能回到這個Task
的最新狀態,無論他們是如何啟動的。這非常有用,例如,像Browser
應用程序,這里有很多的狀態(例如多個打開的Tab
),用戶不想丟失這些狀態。
android:clearTaskOnLaunch
用來標記是否從Task中清除所有的Activity
,除了根Activity
外(每當從主畫面重新啟動時)
??“true”
,表示總是清除至它的根Activity
,“false”
表示不。默認值是“false”
。
??這個特性只對啟動一個新的Task
的Activity
(根Activity
)有意義;對Task
中其它的Activity
忽略。
??當這個值為“true”
,每次用戶重新啟動這個Task
時,都會進入到它的根Activity
中,不管這個Task
最后在做些什么,也不管用戶是使用BACK
還是HOME
離開的。當這個值為“false”
時,可能會在一些情形下(參考alwaysRetainTaskState
特性)清除Task
的Activity
,但不總是。
??假設,某人從主畫面啟動了Activity P
,并從那里遷移至Activity Q
。接下來用戶按下HOME
,然后返回Activity P
。一般,用戶可能見到的是Activity Q
,因為它是P
的Task
中最后工作的內容。然而,如果P
設定這個特性為“true”
,當用戶按下HOME
并使這個Task
再次進入前臺時,其上的所有的Activity
(在這里是Q
)都將被清除。因此,當返回到這個Task
時,用戶只能看到P
。
??如果這個特性和allowTaskReparenting
都設定為“true”
,那些能重新宿主的Activity
會移動到共享affinity
的Task
中;剩下的Activity
都將被拋棄,如上所述。
android:finishOnTaskLaunch
用來標記當用戶再次啟動它的Task
(在主畫面選擇這個Task
)時已經存在的Activity
實例是否要關閉(結束)
?“true”
,表示應該關閉,“false”
表示不關閉。默認值是“false”
。
?如果這個特性和allowTaskReparenting
都設定為“true”
,這個特性勝出。Activity
的affinity
忽略。這個Activity
不會重新宿主,但是會銷毀。
android:launchMode
用于指示Activity
如何啟動。這里有四種模式,與Intent
對象中的Activity Flags(FLAG_ACTIVITY_*變量)
共同作用,來決定Activity
如何啟動來處理Intent
。它們是:
??"standard"
??"singleTop"
??"singleTask"
??"singleInstance"
??默認模式是“standard”
。
??前面文章:“Android四種Activity的加載模式”
已經詳細描述,這里就不做描述了.
android:noHistory
用于標記當用戶從Activity
上離開并且它在屏幕上不再可見時Activity
是否從Activity stack
中清除并結束(調用finish()方法)——“true”
,表示它應該關閉,“false”
,表示不需要。默認值是“false”
。
??“true”
值意味著Activity
不會留下歷史痕跡。因為它不會在Activity stack
的Task
中保留,因此,用戶不能返回它。
??比如啟用界面的就可以借用這個。
android:taskAffinity
這就是本文所描述的任務共用性。
??Activity
為Task
擁有的一個affinity。擁有相同的affinity
的Activity
理論上屬于相同的Task
(在用戶的角度是相同的“應用程序”)。Task
的affinity
是由它的根Activity
決定的。
??affinity
決定兩件事情——Activity
重新宿主的Task(參考allowTaskReparenting
特性)和使用FLAG_ACTIVITY_NEW_TASK
標志啟動的Activity
宿主的Task
。
??默認情況,一個應用程序中的所有Activity
都擁有相同的affinity
。捏可以設定這個特性來重組它們,甚至可以把不同應用程序中定義的Activity
放置到相同的Task
中。為了明確Activity
不宿主特定的Task
,設定該特性為空的字符串。
??如果這個特性沒有設置,Activity
將從應用程序的設定那里繼承下來(參考<application>
元素的taskAffinity
特性)。應用程序默認的affinity
的名字是<manifest>
元素中設定的package
名。
跟Task有關的Intent對象中設置的Flag
FLAG_ACTIVITY_BROUGHT_TO_FRONT
這個標志一般不是由程序代碼設置的,如在launchMode
中設置singleTask
模式時系統幫你設定。
FLAG_ACTIVITY_CLEAR_TOP
如果設置,并且這個Activity
已經在當前的Task
中運行,因此,不再是重新啟動一個這個Activity
的實例,而是在這個Activity
上方的所有Activity
都將關閉,然后這個Intent會作為一個新的Intent
投遞到老的Activity(現在位于頂端)中。
??例如,假設一個Task
中包含這些Activity
:A,B,C,D。如果D調用了startActivity()
,并且包含一個指向Activity B
的Intent
,那么,C和D都將結束,然后B接收到這個Intent
,因此,目前stack
的狀況是:A,B。
??上例中正在運行的Activity B
既可以在onNewIntent()
中接收到這個新的Intent
,也可以把自己關閉然后重新啟動來接收這個Intent
。如果它的啟動模式聲明為“multiple”
(默認值),并且你沒有在這個Intent
中設置FLAG_ACTIVITY_SINGLE_TOP
標志,那么它將關閉然后重新創建;對于其它的啟動模式,或者在這個Intent
中設置FLAG_ACTIVITY_SINGLE_TOP
標志,都將把這個Intent
投遞到當前這個實例的onNewIntent()
中。
??這個啟動模式還可以與FLAG_ACTIVITY_NEW_TASK
結合起來使用:用于啟動一個Task
中的根Activity
,它會把那個Task
中任何運行的實例帶入前臺,然后清除它直到根Activity
。這非常有用,例如,當從Notification Manager
處啟動一個Activity
。
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
如果設置,這將在Task
的Activity stack
中設置一個還原點,當Task
恢復時,需要清理Activity
。也就是說,下一次Task
帶著FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
標記進入前臺時(典型的操作是用戶在主畫面重啟它),這個Activity
和它之上的都將關閉,以至于用戶不能再返回到它們,但是可以回到之前的Activity
。
??這在你的程序有分割點的時候很有用。例如,一個e-mail
應用程序可能有一個操作是查看一個附件,需要啟動圖片瀏覽Activity
來顯示。這個Activity
應該作為e-mail
應用程序Task
的一部分,因為這是用戶在這個Task
中觸發的操作。然而,當用戶離開這個Task
,然后從主畫面選擇e-mail app
,我們可能希望回到查看的會話中,但不是查看圖片附件,因為這讓人困惑。通過在啟動圖片瀏覽時設定這個標志,瀏覽及其它啟動的Activity
在下次用戶返回到mail
程序時都將全部清除。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果設置,新的Activity
不會在最近啟動的Activity
的列表中保存。
FLAG_ACTIVITY_FORWARD_RESULT
如果設置,并且這個Intent
用于從一個存在的Activity
啟動一個新的Activity
,那么,這個作為答復目標的Activity
將會傳到這個新的Activity
中。這種方式下,新的Activity
可以調用setResult(int)
,并且這個結果值將發送給那個作為答復目標的Activity
。
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
這個標志一般不由應用程序代碼設置,如果這個Activity
是從歷史記錄里啟動的(常按HOME
鍵),那么,系統會幫你設定。
FLAG_ACTIVITY_MULTIPLE_TASK
不要使用這個標志,除非你自己實現了應用程序啟動器。與FLAG_ACTIVITY_NEW_TASK
結合起來使用,可以禁用把已存的Task
送入前臺的行為。當設置時,新的Task
總是會啟動來處理Intent
,而不管這是是否已經有一個Task
可以處理相同的事情。
??由于默認的系統不包含圖形Task管理功能,因此,你不應該使用這個標志,除非你提供給用戶一種方式可以返回到已經啟動的Task。
??如果FLAG_ACTIVITY_NEW_TASK
標志沒有設置,這個標志被忽略。
FLAG_ACTIVITY_NEW_TASK
如果設置,這個Activity
會成為歷史stack
中一個新Task
的開始。一個Task
(從啟動它的Activity
到下一個Task
中的Activity
)定義了用戶可以遷移的Activity
原子組。Task
可以移動到前臺和后臺;在某個特定Task
中的所有Activity
總是保持相同的次序。
??這個標志一般用于呈現“啟動”類型的行為:它們提供用戶一系列可以單獨完成的事情,與啟動它們的Activity
完全無關。
??使用這個標志,如果正在啟動的Activity
的Task
已經在運行的話,那么,新的Activity
將不會啟動;代替的,當前Task
會簡單的移入前臺。參考FLAG_ACTIVITY_MULTIPLE_TASK
標志,可以禁用這一行為。
??這個標志不能用于調用方對已經啟動的Activity
請求結果。
FLAG_ACTIVITY_NO_ANIMATION
如果在Intent
中設置,并傳遞給Context.startActivity()
的話,這個標志將阻止系統進入下一個Activity
時應用Acitivity
遷移動畫。這并不意味著動畫將永不運行——如果另一個Activity
在啟動顯示之前,沒有指定這個標志,那么,動畫將被應用。這個標志可以很好的用于執行一連串的操作,而動畫被看作是更高一級的事件的驅動。
FLAG_ACTIVITY_NO_HISTORY
如果設置,新的Activity
將不再歷史stack
中保留。用戶一離開它,這個Activity
就關閉了。這也可以通過設置noHistory
特性。
FLAG_ACTIVITY_NO_USER_ACTION
如果設置,作為新啟動的Activity
進入前臺時,這個標志將在Activity
暫停之前阻止從最前方的Activity
回調的onUserLeaveHint()
。
??典型的,一個Activity
可以依賴這個回調指明顯式的用戶動作引起的Activity
移出后臺。這個回調在Activity
的生命周期中標記一個合適的點,并關閉一些Notification
。
??如果一個Activity
通過非用戶驅動的事件,如來電或鬧鐘,啟動的,這個標志也應該傳遞給Context.startActivity
,保證暫停的Activity
不認為用戶已經知曉其Notification
。
FLAG_ACTIVITY_PREVIOUS_IS_TOP
If set and this intent is being used to launch a new activity from an existing one, the current activity will not be counted as the top activity for deciding whether the new intent should be delivered to the top instead of starting a new one. The previous activity will be used as the top, with the assumption being that the current activity will finish itself immediately.
FLAG_ACTIVITY_REORDER_TO_FRONT
如果在Intent
中設置,并傳遞給Context.startActivity()
,這個標志將引發已經運行的Activity
移動到歷史stack
的頂端。
??例如,假設一個Task
由四個Activity
組成:A,B,C,D
。如果D
調用startActivity()
來啟動Activity B
,那么,B
會移動到歷史stack
的頂端,現在的次序變成A,C,D,B
。如果FLAG_ACTIVITY_CLEAR_TOP
標志也設置的話,那么這個標志將被忽略。
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
If set, and this activity is either being started in a new task or bringing to the top an existing task, then it will be launched as the front door of the task. This will result in the application of any affinities needed to have that task in the proper state (either moving activities to or from it), or simply resetting that task to its initial state if needed.
FLAG_ACTIVITY_SINGLE_TOP
如果設置,當這個Activity
位于歷史stack
的頂端運行時,不再啟動一個新的。