很想弄清楚啓動一個Activity和Task(任務)的關係,網上也有不少相關資料,由從源碼來具體分析的,也有針對launchmode來分析,但都不是本身的,理解起來總不是那麼容易,爲此,嘗試着本身去理解其中的邏輯。不過事先須要弄清楚兩個問題:java
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類。android
網上資料顯示在2.3之後的SDK中,Ams將原來的HistoryRecord類從新命名爲ActivityRecord類,並將其原來Ams中的一些處理抽出來成爲一個ActivityStack類,每個Activity實例對應一個ActivityRecord對象,並存放在ActivityStack中,手機一旦啓動,就會啓動一個Ams服務,在Ams服務中有一個ActivityStack實例專門管理手機上的ActivityRecord實例。這樣一來,不具體分析源碼,僅從架構角度來講誰負責管理Activity的問題就清晰多了。web
根據對上面問題的解答,既然Activity是由Ams經過ActivityStack來管理的,那麼這個Task又是幹什麼的呢?架構
以往基於應用(application)的程序開發中,程序具備明確的邊界,一個程序就是一個應用,一個應用爲了實現功能能夠採用開闢新線程甚至新進程來輔助,可是應用與應用之間不能複用資源和功能。而Android引入了基於組件開發的軟件架構,雖然咱們開發android程序,仍然使用一個apk工程一個Application的開發形式,可是對於Aplication的開發就用到了Activity、service等四大組件,其中的每個組件,都是能夠被跨應用複用的哦,這個就是android的神奇之處。app
另外值得一提的是,雖然組件能夠跨應用被調用,可是一個組件所在的進程必須是在組件所在的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來惟一標識,該值在手機重啓時將會被置零。ide
說了這麼多,仍是找一個Task任務最直觀的體現吧。先重啓手機,長按home鍵,發現彈出的最近任務中一個任務也沒有,而後開啓A應用,長按home鍵,會發現有一個A應用的任務,查看手機進程,應該尚未B進程的;在A應用的A組件中調B應用的B組件,此時看手機的進程,除了A進程外,還有個B的進程,可是長按home鍵,能看到的仍是隻有一個A應用的任務。其實這個時候,B應用已經跑起來了,可是對用戶來講,他其實沒有開啓過B應用,因此Task任務自始至終都是從用戶的角度出發而設計的概念,保證用戶的調用邏輯。函數
理清楚了上述兩個概念問題,進入Activity的啓動與Task的關係以前,讓咱們先來了解下啓動一個Activity與apk Application和進程的關係。對Activity啓動過程具體的分析,工程耗時很龐大,網上有個老羅整理的三篇博客,我看了半天仍是雲裏霧裏的,有興趣的能夠查看以下連接:http://blog.csdn.net/luoshengyang/article/details/6685853。我經過我如今的認識和目前經過Demo的測試來看,啓動一個Activity時,Ams首先會去查詢該Activity所在的應用是否開啓,若是沒有開啓則會啓動一個進程去Run這個Application,所以不管經過Launcher仍是經過常規的程序內部調用startActivity來啓動一個Activity,所要啓動的Activity都是跑在其註冊的apk所在的Application進程中(或者該組件android:process指定的進程中),而其TaskID通常是和啓動它的組件所屬的TaskId一直,可是也不盡然,這就要看下面的具體分析了。測試
另外經過對service的應用,能夠得出結論,一個apk,即一個應用(Application)能夠跑在多個進程中,一個進程在一個虛擬機中運行,也即一個apk能夠啓動多個虛擬機。動畫
經過shareuserID能夠將多個apk,跑在同一個進程中。
從而得出結論:一個虛擬機只能跑一個進程,一個進程裏能夠跑多個應用,一個應用也能夠跑在多個進程中,這就是他們的關係。
啓動一個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和singTop方式就夠用了,不須要使用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"
在上述分析中沒有將其它兩個因素引入,主要是本身在這方面接觸的也比較少,並且這三方面因素共同組合會產生不少種不一樣效果,因此就沒作具體展開。轉載一些網友收集的資料以下:
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名。
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的頂端運行時,再也不啓動一個新的。