天天看點

Android中Activity與Task相關的屬性解析

android:allowTaskReparenting

    用來标記Activity能否從啟動的Task移動到有着affinity的Task(當這個Task進入到前台時)——“true”,表示能移動,“false”,表示它必須呆在啟動時呆在的那個Task裡。

    如果這個特性沒有被設定,設定到<application>元素上的allowTaskReparenting特性的值會應用到Activity上。預設值為“false”。

    一般來說,當Activity啟動後,它就與啟動它的Task關聯,并且在那裡耗盡它的整個生命周期。當目前的Task不再顯示時,你可以使用這個特性來強制Activity移動到有着affinity的Task中。典型用法是:把一個應用程式的Activity移到另一個應用程式的主Task中。

    例如,如果e-mail中包含一個web頁的連結,點選它就會啟動一個Activity來顯示這個頁面。這個Activity是由Browser應用程式定義的,但是,現在它作為e-mail Task的一部分。如果它重新宿主到Browser Task裡,當Browser下一次進入到前台時,它就能被看見,并且,當e-mail 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”。

    這些模式可以分成兩大組别,“standard”和“singleTop”一組,“singleTask”和“singleInstance”一組。具有“standard”和“singleTop”啟動模式的Activity可以執行個體化很多次。這些執行個體可以屬于任何Task并且可以位于Activity stack的任何位置。典型的情況是,它們會進入調用startActivity()的Task(除非Intent對象包含FLAG_ACTIVITY_NEW_TASK标志,在這種情況下會選擇一個不同的Task——參考taskAffinity特性)。

    相反的,“singleTask”和“singleInstance”隻能啟動一個Task。它們總是位于Activity stack的底部。甚至,裝置一次隻能擁有一個Activity的執行個體——隻有一個這樣的Task。

    “standard”和“singleTop”模式隻在一種情況下有差别:每次有一個新的啟動“standard”Activity的Intent,就會建立一個新的執行個體來響應這個Intent。每個執行個體處理一個Intent。相似的,一個“singleTop”的Activity執行個體也有可能被建立來處理新的Intent。然而,如果目标Task已經有一個存在的執行個體并且位于stack的頂部,那麼,這個執行個體就會接收到這個新的Intent(調用onNewIntent());不會建立新的執行個體。在其他情況下——例如,如果存在的“singleTop”的Activity執行個體在目标Task中,但不是在stack的頂部,或者它在一個stack的頂部,但不是在目标Task中——新的執行個體都會被建立并壓入stack中。

    “singleTask”和“singleInstance”模式也隻在一種情況下有差别:“singleTask”Activity允許其它Activity成為它的Task的部分。它位于Activity stack的底部,其它Activity(必須是“standard”和“singleTop”Activity)可以啟動加入到相同的Task中。“singleInstance”Activity,換句話說,不允許其它Activity成為它的Task的部分。它是Task中的唯一Activity。如果它啟動其它的Activity,這個Activity會被放置到另一個task中——好像Intent中包含了FLAG_ACTIVITY_NEW_TASK标志。

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的頂端運作時,不再啟動一個新的。

之前提到的,一個Activity可以啟動另一個,即便是定義在不同應用程式中的Activity。例如,假設你想讓使用者顯示一些地方的街景。而這裡已經有一個Activity可以做到這一點,是以,你的Activity所需要做的隻是在Intent對象中添加必要的資訊,并傳遞給startActivity()。地圖浏覽将會顯示你的地圖。當使用者按下BACK鍵,你的Activity會再次出現在螢幕上。

對于使用者來說,看起來好像是地圖浏覽與你的Activity一樣,屬于相同的應用程式,即便是它定義在其它的應用程式裡,并運作在那個應用程式的程序裡。Android通過将這兩個Activity儲存在同一個Task裡來展現這一使用者體驗。簡單來說,一個Task就是使用者體驗上的一個“應用”。它将相關的Activity組合在一起,以stack的方式管理。stack中根Activity啟動Task——典型的,它就是使用者在應用程式啟動欄中選擇的Activity。位于stack頂端的Activity是目前正在運作的——能夠聚焦使用者的動作。當一個Activity啟動另一個,新的Activity進入stack;它成為正在運作的Activity。之前的Activity仍保留在stack中。當使用者按下BACK鍵,目前的Activity從stack中退出,之前的那個成為正在運作的Activity。

stack包含對象,是以,如果一個Task中有多個同一個Activity的執行個體時——多個地圖浏覽,例如——stack為每個執行個體擁有一個獨立的入口。位于stack中的Activity不會重新調整,隻是進入和退出。

一個Task就是一組Activity,不是一個類或者在manifest中定義的一個元素。是以,沒有辦法為Task設定獨立于它的Activity的屬性值。Task的值作為整體在根Activity中設定。例如,下一個章節會讨論Task的“affinity”;那個值就是從Task中的根Activity中讀取的。

Task中的所有Activity作為一個單元一起移動。整個Task(整個Activity stack)可以進入前台或者退到背景。例如,假設目前Task中的stack中有4個Activity——3個位于目前Activity下方。使用者按下HOME鍵,進入到應用程式啟動欄,然後選擇一個新的應用程式(實際上,一個新的Task)。目前Task退到背景,并且新Task中的根Activity會顯示出來。然後,經過一段時間後,使用者回到Home畫面,然後再次選擇前一個應用程式(前一個Task)。那個擁有4個Activity的Task會進入前台。當使用者按下BACK鍵,螢幕不會顯示使用者剛剛離開的Activity(前一個Task的根Activity)。而是,這個stack中的頂端Activity移除,相同Task中的前一個Activity會顯示出來。

剛才描述的行為是Activity和Task的預設行為。但有方法來完全改變它。Task之間的關聯,和一個Task中的一個Activity行為,受啟動Activity的Intent對象中設定的Flag和manifest檔案中Activity的<activity>元素的特性值互動控制。調用者和響應者都有權決定如何發生。

核心的Intent Flag有:

FLAG_ACTIVITY_NEW_TASK

核心的<activity>特性有:

taskAffinity

launchMode

allowTaskReparenting

clearTaskOnLaunch

alwaysRetainTaskState

finishOnTaskLaunch

接下來的章節将描述一些Flag和特性的用法,如何互相影響,以及在使用時的建議。

預設情況下,一個應用程式中的所有Activity都有affinity——也就是說,屬于同一個Task中所有Activity有一個設定。然而,每個Activity都可以在<activity>元素的taskAffinity特性上設定單獨的值。定義在不同應用程式中的Activity可以共享同一個affinity,或者定義在同一個應用程式中的Activity設定不同的affinity。Affinity在兩種環境下工作:Intent對象包含FLAG_ACTIVITY_NEW_TASK标志,和Activity的allowTaskReparenting特性設定為“true”。

FLAG_ACTIVITY_NEW_TASK:

之前描述的,一個Activity一般通過調用startActivity()啟動并加入到Task中。它同調用者一樣,進入同一個Task。然而,如果傳遞給startActivity()的Intent對象中包含FLAG_ACTIVITY_NEW_TASK時,系統會搜尋一個新的Task來容納新的Activity。通常,如标志的名字所示,是一個新的Task。然而,并不是必須是。如果已經存在一個Task與新Activity的affinity相同,這個Activity就會加入到那個Task中。如果不是,啟動一個新的Task。

allowTaskReparenting:

如果一個Activity的allowTaskReparenting特性設定為“true”,它就能從啟動的Task中移到有着相同affinity的Task(這個Task進入到前台的時候)。例如,在一個旅遊的程式中定義了一個可以報告選擇城市的天氣情況的Activity。它和同一個應用程式的其它Activity一樣,有着相同的Affinity(預設的Affinity),并且它允許重新宿主。你的Activity中的一個啟動了天氣預報,是以,它初始化到和你Activity相同的Task中。然而,當旅遊應用程式下一次進入到前台時,天氣預報那個Activity将會重新編排并在那個Task中顯示。

如果從使用者的角度出發,一個.apk檔案包含多個“應用”的話,你可能希望為關聯的Activity設定不同的affinity。

繼續閱讀