Activity、Task、Application關係+Intent啓動Flag

什麼是Android  Application?

簡單來說,一個apk文件就是一個Application。

任何一個AndroidApplication基本上是由一些Activities組成,當用戶與應用程序交互時其所包含的部分Activities具有緊密的邏輯關係,或者各自獨立處理不同的響應。

這些Activities捆綁在一起成爲了一個處理特定需求的Application,並且以“.apk”作爲後綴名存在於文件系統中。

Android平臺默認下的應用程序 例如:Email、Calendar、Browser、Maps、TextMessage、Contacts、Camera和Dialer等都是一個個獨立的Apps。

 

安裝Application的過程也可以簡單理解爲將其所包裹的Activities導入到當前的系統中,如果系統中已經存在了相同的Activities,那麼將會自動將其關聯,而不會重複安裝相同的Activities,避免資源的浪費。

Application卸載的過程也會檢查當前所關聯的Activities是否有被其它Application標籤所關聯,如果僅僅是提供當前的Application使用,那麼將會徹底被移除,相反則不做任何操作。

 

就像我們已經知道的,Application基本上是由四個模塊組成:Activity、Service、ContentProvider 和 Broadcast Receiver,其中Activity是實現應用的主體。

 

什麼是 Activity Stack?

操作應用程序時,有時需要調用多個Activities來完成需求,例如:發送郵件程序,首先是進入郵件主界面,然後啓動一個新的Activity用於填寫新郵件內容,同時可以調出聯繫人列表用於插入收件人信息等等。在這個操作過程中Android平臺有一個專門用於管理Activities堆棧的機制,其可以方便的線性記錄Activities實例,當完成某個操作時,可以通過導航功能返回之前的Activity(通過按操作檯的“Back”按鈕)。

每次啓動新的Activity都將被添加到Activity Stack。用戶可以方便的返回上一個Activity直到HomeScreen,到達HomeScreen後,將無法再繼續查看堆棧記錄(俗話說:到頭了)。如果當前Task被中止(Interrupting thetask),返回到系統主界面後啓動了其它操作,當希望返回到前一個Task繼續執行時,只需要再次通過主界面的Applicationlauncher或者快捷方式啓動這個Task的Root Activity便可返回其中止時的狀態繼續執行。

相對於Views、Windows、Menus和Dialogs而言,Activity是唯一可被記錄在Historystack中的數據,所以當你所設計的應用程序需要用戶由A界面進入到次一級界面B,當完成操作後需要再次返回A,那麼必須考慮將A看作爲Activity,否則將無法從歷史堆棧中返回。

 

什麼是Task

當我們需要一個Activity可以啓動另一個Activity,可能另外一個Activity是定義在不同應用程序中的Activity。

例如,假設你想在你的應用中讓用戶顯示一些地方的街景。而這裏已經有一個Activity可以做到這一點,因此,你的Activity所需要做的只是在Intent對象中添加必要的信息,並傳遞給startActivity()。地圖瀏覽將會顯示你的地圖。當用戶按下BACK鍵,你的Activity會再次出現在屏幕上。

對於用戶來說,看起來好像是地圖瀏覽與你的Activity一樣,屬於相同的應用程序,即便是它定義在其它的應用程序裏,並運行在那個應用程序的進程裏。

Android通過將這兩個Activity保存在同一個Task裏來體現這一用戶體驗。簡單來說,一個Task就是用戶體驗上的一個“應用”。 
它將相關的Activity組合在一起,以stack的方式管理(就是前面提到的Activity Stack),這就是Task。

 

在Android平臺上可以將task簡單的理解爲幽多個Activity共同協作完成某項應用,而不管Activity具體屬於哪個Application,

通過下圖可以更清晰的理解Application、task、Activity三者之間的關係:

image

 

Task 有啥用?

我們用過Android的手機就會知道有下面的場景:

假設我們首先在用IReader在看書,從選書到具體書的閱讀界面,這是有好幾個Activity。我們每一個點擊的Activity都被放在閱讀這個Task對應的ActivityStack中了,這可以放我們通過回退鍵返回每一個前面的Activity。

我們在閱讀到一半時,想看看Sina微博,按Home鍵離開了IReader。

在Sina微博界面也是有多個Activity,我們一步到閱讀界面。這時候我們每一個點擊的Activity都被放在Sina微博這個Task對應的ActivityStack中了,這可以放我們通過回退鍵返回每一個前面的Activity。

我們這時候再回到IReader讀書界面,原先的狀態還是保留的。

顯然每一個Task有自己的 Activity Stack。

Task就是這樣爲了方便人們使用手機而設置的,就像前面提到的場景Task可以跨Application。

 

下面這個圖從另外一個角度描述了Application Task Activities的關係

image

 

Task通過Application launcher、Home screen的快捷方式或者 由 “RecentTasks”(長時間按住Home鍵)最近使用過的Task記錄中啓動。

當從一個Activity中啓動另外一個Activity時,Back鍵將作用於返回前一個Activity,與此同時新開啓的Activity將被添加到Activity Stack中。

有關更詳細的可以參看這篇文章:

[譯]關於Activity和Task的設計思路和方法 
http://blogold.chinaunix.net/u2/85193/showart_1966109.html 

 

參考資料:

http://skyswim42.egloos.com/3127700

關於Activity和Task的設計思路和方法 
http://blogold.chinaunix.net/u2/85193/showart_1966109.html

Android Task 
http://www.apkbus.com/forum.php?mod=viewthread&tid=146

 

Android四種Activity的加載模式

 

建議首先閱讀下面兩篇文章,這樣纔可以更好的理解Activity的加載模式:

  Android的進程,線程模型:
  http://blog.csdn.net/AndroidBluetooth/archive/2011/06/15/6547166.aspx其中對“Android的單線程模型”的描述,明白Activity的一些注意事項。

  Android Application Task Activities的關係 
  http://www.cnblogs.com/ghj1976/archive/2011/04/29/2032412.html 尤其要明白 Task 是啥。

 一個Activty的生命週期

  Activty的生命週期的也就是它所在進程的生命週期。

  每一個活動(Activity)都處於某一個狀態,對於開發者來說,是無法控制其應用程序處於某一個狀態的,這些均由系統來完成。 
  但是當一個活動的狀態發生改變的時候,開發者可以通過調用 onXX() 的方法獲取到相關的通知信息。

  在實現 Activity 類的時候,通過覆蓋( override )這些方法即可在你需要處理的時候來調用。

  • onCreate:當活動第一次啓動的時候,觸發該方法,可以在此時完成活動的初始化工作。 
    onCreate 方法有一個參數,該參數可以爲空( null ),也可以是之前調用 onSaveInstanceState()方法保存的狀態信息。
  • onStart :該方法的觸發表示所屬活動將被展現給用戶。
  • onResume :當一個活動和用戶發生交互的時候,觸發該方法。
  • onPause:當一個正在前臺運行的活動因爲其他的活動需要前臺運行而轉入後臺運行的時候,觸發該方法。這時候需要將活動的狀態持久化,比如正在編輯的數據庫記錄等。
  • onStop :當一個活動不再需要展示給用戶的時候,觸發該方法。如果內存緊張,系統會直接結束這個活動,而不會觸發 onStop方法。所以保存狀態信息是應該在onPause時做,而不是onStop時做。活動如果沒有在前臺運行,都將被停止或者Linux管理進程爲了給新的活動預留足夠的存儲空間而隨時結束這些活動。因此對於開發者來說,在設計應用程序的時候,必須時刻牢記這一原則。在一些情況下,onPause方法或許是活動觸發的最後的方法,因此開發者需要在這個時候保存需要保存的信息。
  • onRestart :當處於停止狀態的活動需要再次展現給用戶的時候,觸發該方法。
  • onDestroy :當活動銷燬的時候,觸發該方法。和 onStop方法一樣,如果內存緊張,系統會直接結束這個活動而不會觸發該方法。
  • onSaveInstanceState:系統調用該方法,允許活動保存之前的狀態,比如說在一串字符串中的光標所處的位置等。 
    通常情況下,開發者不需要重寫覆蓋該方法,在默認的實現中,已經提供了自動保存活動所涉及到的用戶界面組件的所有狀態信息。 

 Activity棧

  上面提到開發者是無法控制Activity的狀態的,那Activity的狀態又是按照何種邏輯來運作的呢?這就要知道Activity 棧。

  每個Activity的狀態是由它在Activity棧(是一個後進先出LIFO,包含所有正在運行Activity的隊列)中的位置決定的。

  當一個新的Activity啓動時,當前的活動的Activity將會移到Activity棧的頂部。

  如果用戶使用後退按鈕返回的話,或者前臺的Activity結束,在棧上的Activity將會移上來並變爲活動狀態。如下圖所示:

  一個應用程序的優先級是受最高優先級的Activity影響的。當決定某個應用程序是否要終結去釋放資源,Android內存管理使用棧來決定基於Activity的應用程序的優先級。

  Activity狀態 
  一般認爲Activity有以下四種狀態:

  活動的:當一個Activity在棧頂,它是可視的、有焦點、可接受用戶輸入的。Android試圖盡最大可能保持它活動狀態,殺死其它Activity來確保當前活動Activity有足夠的資源可使用。當另外一個Activity被激活,這個將會被暫停。 
  暫停:在很多情況下,你的Activity可視但是它沒有焦點,換句話說它被暫停了。有可能原因是一個透明或者非全屏的Activity被激活。 
  當被暫停,一個Activity仍會當成活動狀態,只不過是不可以接受用戶輸入。在極特殊的情況下,Android將會殺死一個暫停的Activity來爲活動的Activity提供充足的資源。當一個Activity變爲完全隱藏,它將會變成停止。 
  停止:當一個Activity不是可視的,它“停止”了。這個Activity將仍然在內存中保存它所有的狀態和會員信息。儘管如此,當其它地方需要內存時,它將是最有可能被釋放資源的。當一個Activity停止後,一個很重要的步驟是要保存數據和當前UI狀態。一旦一個Activity退出或關閉了,它將變爲待用狀態。 
  待用:在一個Activity被殺死後和被裝在前,它是待用狀態的。待用Acitivity被移除Activity棧,並且需要在顯示和可用之前重新啓動它。

 activity的四種加載模式

  在android的多activity開發中,activity之間的跳轉可能需要有多種方式,有時是普通的生成一個新實例,有時希望跳轉到原來某個activity實例,而不是生成大量的重複的activity。加載模式便是決定以哪種方式啓動一個跳轉到原來某個Activity實例。

  在android裏,有4種activity的啓動模式,分別爲:

  • standard: 標準模式,一調用startActivity()方法就會產生一個新的實例。
  • singleTop:如果已經有一個實例位於Activity棧的頂部時,就不產生新的實例,而只是調用Activity中的newInstance()方法。如果不位於棧頂,會產生一個新的實例。
  • singleTask: 會在一個新的task中產生這個實例,以後每次調用都會使用這個,不會去產生新的實例了。
  • singleInstance:這個跟singleTask基本上是一樣,只有一個區別:在這個模式下的Activity實例所處的task中,只能有這個activity實例,不能有其他的實例。

  這些啓動模式可以在功能清單文件AndroidManifest.xml中進行設置,中的launchMode屬性。

  相關的代碼中也有一些標誌可以使用,比如我們想只啓用一個實例,則可以使用Intent.FLAG_ACTIVITY_REORDER_TO_FRONT標誌,這個標誌表示:如果這個activity已經啓動了,就不產生新的activity,而只是把這個activity實例加到棧頂來就可以了。

Intent intent = new Intent(ReorderFour.this, ReorderTwo.class);  intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);  startActivity(intent);  

  Activity的加載模式受啓動Activity的Intent對象中設置的Flag和manifest文件中Activity的元素的特性值交互控制。

  下面是影響加載模式的一些特性

  核心的Intent Flag有: 
  FLAG_ACTIVITY_NEW_TASK 
  FLAG_ACTIVITY_CLEAR_TOP 
  FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 
  FLAG_ACTIVITY_SINGLE_TOP 
  核心的特性有: 
  taskAffinity 
  launchMode 
  allowTaskReparenting 
  clearTaskOnLaunch 
  alwaysRetainTaskState 
  finishOnTaskLaunch

四種加載模式的區別

 所屬task的區別

  一般情況下,“standard”和”singleTop”的activity的目標task,和收到的Intent的發送者在同一個task內,就相當於誰調用它,它就跟誰在同一個Task中。

  除非Intent包括參數FLAG_ACTIVITY_NEW_TASK。如果提供了FLAG_ACTIVITY_NEW_TASK參數,會啓動到別的task裏。 
  “singleTask”和”singleInstance”總是把要啓動的activity作爲一個task的根元素,他們不會被啓動到一個其他task裏。

 是否允許多個實例

  “standard”和”singleTop”可以被實例化多次,並且是可以存在於不同的task中;這種實例化時一個task可以包括一個activity的多個實例; 
  “singleTask”和”singleInstance”則限制只生成一個實例,並且是task的根元素。 
  singleTop要求如果創建intent的時候棧頂已經有要創建的Activity的實例,則將intent發送給該實例,而不創建新的實例。

 是否允許其它activity存在於本task內

  “singleInstance”獨佔一個task,其它activity不能存在那個task裏;

  如果它啓動了一個新的activity,不管新的activity的launch mode如何,新的activity都將會到別的task裏運行(如同加了FLAG_ACTIVITY_NEW_TASK參數)。 
  而另外三種模式,則可以和其它activity共存。

 是否每次都生成新實例

  “standard”對於每一個啓動Intent都會生成一個activity的新實例; 
  “singleTop”的activity如果在task的棧頂的話,則不生成新的該activity的實例,直接使用棧頂的實例,否則,生成該activity的實例。

  比如:

  現在task棧元素爲A-B-C-D(D在棧頂),這時候給D發一個啓動intent,如果D是“standard”的,則生成D的一個新實例,棧變爲A-B-C-D-D。 
  如果D是singleTop的話,則不會生產D的新實例,棧狀態仍爲A-B-C-D 
  如果這時候給B發Intent的話,不管B的launchmode是”standard” 還是 “singleTop”,都會生成B的新實例,棧狀態變爲A-B-C-D-B。

  “singleInstance”是其所在棧的唯一activity,它會每次都被重用。

  “singleTask” 如果在棧頂,則接受intent,否則,該intent會被丟棄,但是該task仍會回到前臺。當已經存在的activity實例處理新的intent時候,會調用onNewIntent()方法,如果收到intent生成一個activity實例,那麼用戶可以通過back鍵回到上一個狀態;如果是已經存在的一個activity來處理這個intent的話,用戶不能通過按back鍵返回到這之前的狀態。

 

原文地址:http://kb.cnblogs.com/page/99664/

 

  參考資料

  Android的七巧板Activity之一 Activity的生命週期 
  http://winuxxan.blog.51cto.com/2779763/502523

  Android的七巧板Activity之二 Activity的加載模式 
  http://winuxxan.blog.51cto.com/2779763/504047

  Android Activity生命週期 
  http://www.haoni.org/2011/02/25/androidactivityshengmingzhouqi/

  android中activity的四種加載模式 
  http://blog.csdn.net/pcwings/archive/2010/09/19/5895197.aspx

  區分Activity的四種加載模式 
  http://marshal.easymorse.com/archives/2950

  Hello Android 第三版 (二) 
  http://blog.csdn.net/cqwty/archive/2010/09/08/5870219.aspx

  只生成一個Activity的實例 
  http://www.eoeandroid.com/home-space-uid-43043-do-blog-id-6.html

  activity的啓動方式(launch mode) 
  http://liubin.nanshapo.com/2010/12/23/activity-launch-mode/

  Android應用程序模型:應用程序,任務,進程和線程 
  http://blog.csdn.net/iefreer/archive/2009/08/18/4460196.aspx

 

關於activity的四種加載模式,我結合網上牛人的例子,android開發指南以及自己的測試寫成一篇文檔,編碼格式utf-8。

下載地址:http://download.csdn.net/source/3368975

----------------------------------------------------------

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(),並且包含一個指向ActivityB的Intent,那麼,C和D都將結束,然後B接收到這個Intent,因此,目前stack的狀況是:A,B。     上例中正在運行的ActivityB既可以在onNewIntent()中接收到這個新的Intent,也可以把自己關閉然後重新啓動來接收這個Intent。如果它的啓動模式聲明爲“multiple”(默認值),並且你沒有在這個Intent中設置FLAG_ACTIVITY_SINGLE_TOP標誌,那麼它將關閉然後重新創建;對於其它的啓動模式,或者在這個Intent中設置FLAG_ACTIVITY_SINGLE_TOP標誌,都將把這個Intent投遞到當前這個實例的onNewIntent()中。     這個啓動模式還可以與FLAG_ACTIVITY_NEW_TASK結合起來使用:用於啓動一個Task中的根Activity,它會把那個Task中任何運行的實例帶入前臺,然後清除它直到根Activity。這非常有用,例如,當從NotificationManager處啓動一個Activity。

 

FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET    

  如果設置,這將在Task的Activitystack中設置一個還原點,當Task恢復時,需要清理Activity。也就是說,下一次Task帶着FLAG_ACTIVITY_RESET_TASK_IF_NEEDED標記進入前臺時(典型的操作是用戶在主畫面重啓它),這個Activity和它之上的都將關閉,以至於用戶不能再返回到它們,但是可以回到之前的Activity。     這在你的程序有分割點的時候很有用。例如,一個e-mail應用程序可能有一個操作是查看一個附件,需要啓動圖片瀏覽Activity來顯示。這個Activity應該作爲e-mail應用程序Task的一部分,因爲這是用戶在這個Task中觸發的操作。然而,當用戶離開這個Task,然後從主畫面選擇e-mailapp,我們可能希望回到查看的會話中,但不是查看圖片附件,因爲這讓人困惑。通過在啓動圖片瀏覽時設定這個標誌,瀏覽及其它啓動的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 activityfrom an existing one, the current activity will not be counted asthe top activity for deciding whether the new intent should bedelivered to the top instead of starting a new one. The previousactivity will be used as the top, with the assumption being thatthe current activity will finish itself immediately.

 

FLAG_ACTIVITY_REORDER_TO_FRONT    

  如果在Intent中設置,並傳遞給Context.startActivity(),這個標誌將引發已經運行的Activity移動到歷史stack的頂端。     例如,假設一個Task由四個Activity組成:A,B,C,D。如果D調用startActivity()來啓動ActivityB,那麼,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 taskor bringing to the top an existing task, then it will be launchedas the front door of the task. This will result in the applicationof any affinities needed to have that task in the proper state(either moving activities to or from it), or simply resetting thattask to its initial state if needed.

 

FLAG_ACTIVITY_SINGLE_TOP     

  如果設置,當這個Activity位於歷史stack的頂端運行時,不再啓動一個新的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章