Android下的任務和Activity棧

一個activity可以啓動另一個,包括那些定義在不同應用程序中的。假設,例如,你想讓用戶顯示一些地方的街道地圖。已經有一個activity可以做這個事,所以你的activity所要做的就是將行爲對象和需要的信息放在一起,並將它們傳遞給startActivity()。 地圖查看器將顯示這個地圖。當用戶按下後退按鈕時,你的activity又重新顯示在屏幕上了。 
    對用戶來說,這個地圖查看器看起來就像是你的應用程序的一部分,即使它定義在另外的應用程序中並運行在那個程序的進程中。Android 通過保持所有的activity在同一個任務中來保持用戶體驗。簡單的的說,任務就是用戶所體驗到的“應用程序”。它是一組相關的activity,分配到一個棧中。棧中的根activity,是任務的開始——一般來說,它是用戶組應用程序加載器中選擇的activity。在棧頂的activity正是當前正在運行的——集中處理用戶動作的那個。當一個activity啓動了另外一個,這個新的activity將壓入棧中,它將成爲正在運行中的 activity。前一個activity保留在棧中。當用戶按下後退按鍵,當前的這個activity將中棧中彈出,而前面的那個activity恢復成運行中狀態。 
     棧包含了對象,如果一個棧有多於一個相同的Activity的子類的實例打開——比如,多個地圖查看器——這個棧分別擁有每個實例的入口。棧中的activity不能重新排列,只能壓入和彈出。 
    任務是一些activity組成的棧,不是清單文件中的類或元素。所以沒有辦法在獨立於它包含的activity的條件下,設置它的值。任務的值作爲一個整體設置在根activity中。例如,下一節將討論“任務的親和性”;這個值是從根activity親和性中讀取出來的。 

    一個任務中的所有activity一起作爲一個單元。整個任務(整個activity棧)可以移動到前臺或者後臺.假設,例如,當前的任務有四個 activity在棧中——三個在當前的activity之下。用戶按下了HOME鍵,進入了應用程序加載器,選擇了一個新的程序(實際上,是一個新的任務)。當前的任務進入了後臺,新任務的根activity顯示出來。然後,過了一會,用戶退回到主界面,又重新選擇了前一個應用程序(前一個任務),棧中有四個activity的那個任務,現在出現在了前臺。當用戶按下BACK按鍵,屏幕就不會再顯示用戶剛剛離開的那個activity,而是刪除棧頂的 activity,同任務中的前一個activity將被顯示出來。 

     剛纔說明的那些行爲,是activity和任務的默認行爲。但是有也辦法修改它的所有方面。activity和任務的關聯,activity在任務中的行爲,受控於啓動activity的行爲對象的標誌位和清單文件中的<activity> 元素的屬性的互相作用。請求者和相應着都要說明發生了什麼。 


   在這裏,主要的行爲標誌爲是: 



FLAG_ACTIVITY_NEW_TASK  
FLAG_ACTIVITY_CLEAR_TOP  
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED  
FLAG_ACTIVITY_SINGLE_TOP 


       主要的<activity> 屬性是: 



taskAffinity  
launchMode  
allowTaskReparenting  
clearTaskOnLaunch  
alwaysRetainTaskState  
finishOnTaskLaunch 


       下面一節將說明這些標誌和屬性都有什麼用,他們之間怎麼互相影響,應該用什麼樣的方案來控制它們的使用。


親和性和新任務 


        默認情況下,應用程序中的所有activity,都有一個對於其它activity的親和性—這是一個對於同一個任務中的其他activity的優先權,然後,通過  <activity>元素的 taskAffinity 屬性可以可以分別爲每一個activity設置親和性。不同應用程序定義的activity可以共享同一個親和性,或者同一個應用程序定義的 activity可以指定不同的親和性。親和性在兩種情況下發揮作用:當行爲對象啓動了一個包含 FLAG_ACTIVITY_NEW_TASK標誌的activity,和當一個activity的allowTaskReparenting 屬性設置爲“true”。 


FLAG_ACTIVITY_NEW_TASK  標誌 
        

        正如前面描述的,一個新的activity,默認情況下,被加載進調用startActivity()方法的activity對象所在的那個任務中。它被壓入和調用者所在的同一個棧中,但是,如果行爲對象在調用startActivity()方法時傳遞了FLAG_ACTIVITY_NEW_TASK標記,系統將用一個不同的任務來容納這個新的activity。通常,就像這個標記的名字所代表的。它是一個新任務,但是,它不必非要這樣。如果已經存在一個和這個activity親和性相同的任務,這個activity就會載入到那個任務中,如果不是的話,纔會啓動新任務。 


allowTaskReparenting  屬性 


        如果activity的allowTaskReparenting 屬性設置爲“true”,它就能從他啓動時所在的任務移動到另一個出現在前臺的任務。例如,假設有一個activity可以根據選擇的城市包括天氣情況,它作爲一個旅行應用程序的一部分。它和同一個應用程序中的其他activity有同樣的親和性(默認的親和性)並且允許重組。你的一個activity開啓了天氣報告器,所以它屬於同一個任務中的這個activity,然而,當旅行應用程序開始運行時,天氣報告器將被重新分配並顯示到那個任務中。 


啓動模式 


        有4中不同的啓動模式可以分配給 <activity> 元素的  launchMode  屬性。 


"standard" (默認的模式)  
"singleTop "  
"singleTask"  
"singleInstance" 


        這些模式主要區別在以下四點: 



哪個任務存放着activity,用來對行爲進行響應。 對“standard ”和“singleTop ”模式來說,這個任務是產生行爲(並且調用startActivity() )的那個——除非行爲對象包含了 FLAG_ACTIVITY_NEW_TASK 標記。在這種情況下,像前面那節Affinities and new tasks  描述的一樣,將會選擇一個不同的任務。 
它們是否可以有多個實例。 "standard "和“singleTop ”類型的activity可以被實例化多次。它們可以屬於多個任務,一個特定的任務也可以擁有同一個activity的多個實例。 

作爲比較"singleTask "和"singleInstance "類型的activity只限定有一個實例。因爲這些activity是任務的根。這個限制意味着,在設備上不能同時有超過一個任務的實例。 

singleTask每次relaunch都會將棧清空,而且一個設備只有一個singleTask Acitivty實例)。

是否能有其他的activity在它所在的任務中。"singleInstance " 類型的activity是它所在任務中唯一的activity。如果它啓動了其他的activity,不管那個activity的啓動模式如何,它都會加載到一個不同的任務中——好像行爲對象中的FLAG_ACTIVITY_NEW_TASK 標記。在其他的方面,"singleInstance "和"singleTask "模式是相同的。 
其他三種模式運行任務中有多個activity。"singleTask "總是任務中的根activity,但是它可以啓動其他的activity並分配到它所在的任務中。"standard "和"singleTop "類型的activity可以出現在任務中的任何地方。 
是否啓動一個新的實例來處理一個新的行爲。 對默認的"standard "模式來說,對於每一個行爲都會創建一個新的實例來響應。每個實例只處理一個行爲。對於"singleTop "模式,如果一個已經存在的實例位於目標任務activity棧的棧頂,那麼他將被重用來處理這個行爲。如果它不在棧頂,它將不會被重用,而是爲行爲創建一個新的實例,並壓入棧中。 

例如,假設,一個任務的activity棧由根activity A和 B,C,D從上到下按這樣的順序組成,所以這個棧就是A-B-C-D。一個行爲指向類型爲D的activity。如果D是默認的"standard "加載模式,一個新的實例會被啓動,棧現在就是這樣A-B-C-D-D。但是,如果D的加載模式是"singleTop ",已經存在的實例會用來處理這個行爲(因爲它在棧的頂端)並且棧中還應該是A-B-C-D。 
   在前面提到,"singleTask "和"singleInstance "類型的activity最多隻有一個實例,所以他們的實例應該會處理每個新的行爲。"singleInstance "類型的activity總是在棧的頂端(因爲他是任務中唯一的一個activity),所以總是能夠適當的處理行爲。然而,"singleTask "類型的activity也許會有其他的activity在它的上面。如果是這樣的話,那就不能處理這個行爲,這個行爲被丟棄。(即使這個行爲被丟棄了,它的到來也會導致那些應該保留不變任務顯示到前臺來)。 


   當一個activity被要求處理一個新的行爲時,行爲對象會通過調用activity的 onNewIntent()  方法傳遞進來(最初啓動activity的行爲可以通過調用getIntent() 方法獲得)。 


       注意,當創建一個新的activity實例來處理一個新的行爲時,用戶總是能夠通過按下BACK按鍵退回到前面的狀態(前一個activity)。但是當一個已經存在的activity實例處理一個新的行爲時,用戶不能通過按下BACK按鍵退回到前面的狀態。 



      更多關於加載模式的內容,請看關於 <activity>  的描述。 




清理棧 




     如果用戶離開一個任務很長時間。系統將清除除了根activity之外的所有activity。當用戶重新回到任務中時,像是用戶離開了它,除了只有最初的activity還在。這個理念是這樣的,過了一段時間,用戶很可能放棄之前所做的事情,回到任務去做一些新的事情。 



     這只是默認情況,有一些activity的屬性可以控制和修改它。 



alwaysRetainTaskState  屬性 


       如果一個任務的根activity的這個屬性設置成了"true",那麼剛纔提到的那些默認行爲就不會發生。這個任務保留所有的activity,甚至經過了很長一段時間。 



clearTaskOnLaunch  屬性 
        
       如果任務的根activity的這個屬性設置成了”true“,那麼只要用戶離開了任務並返回,就會清除除了根activity之外的所有activity。換句話說,它和alwaysRetainTaskState正好相反,當用戶返回到任務時,總是恢復到最初的狀態,不管離開了多長時間。 


finishOnTaskLaunch  屬性 


這個屬性和clearTaskOnLaunch類似,但是它作用於單個activity,而不是整個任務。它可以導致任何的activity離開,包括根activity。當它設置成"true"的時候,作爲任務一部分的activity只對當前會話有效。如果用戶離開然後返回到任務中。它將不再出現。 


       還有其他的方法強制將activity從棧中移除。如果一個行爲對象包含了 FLAG_ACTIVITY_CLEAR_TOP  標誌,它的目標任務中已經有了一個這樣類型的activity實例,所有棧中位於這個實例之上的activity都會被清除,所以這個實例就會出現在棧頂並且對行爲進行響應。如果activity被設計成"standard"模式,它也將會從棧中被清除,並且會啓動新的實例來處理到來的行爲。這是因爲當設置成”standard“模式後,對每個新的行爲都會創建一個新的實例。 


      FLAG_ACTIVITY_CLEAR_TOP經常 和FLAG_ACTIVITY_NEW_TASK一起使用。當一起使用時,這些標誌是定位一個在另一個任務中存在的activity並且將它放在一個可以響應行爲的地方的一種方法。 


啓動任務 


    Activity通過將行爲過濾器”android .intent.action.MAIN“設置爲指定動作和"android .intent.category.LAUNCHER"作爲指定類型,來成爲任務的入口。(前面關於行爲過濾器那一些討論的例子)。這種類型的過濾器會讓activity的圖標和標籤顯示在應用程序加載器上面,可以讓用戶啓動和返回activity。 


    第二個能力更爲重要,用戶應該可以在離開一個任務一段時間後返回。因爲這樣,能夠初始化任務的"singleTask"和"singleInstance"模式,只能夠用在那些擁有MAIN 和LAUNCHER 過濾器的activity中。想像一下如果沒有這兩個過濾器會發生什麼:一個行爲啓動了"singleTask"模式的activity,啓動了一個新的任務並且用戶花了一些時間在這個任務上。然後用戶按下了HOME鍵,這個任務被隱藏到了後臺。因爲沒有在應用程序加載器上顯示它,所以就沒有辦法返回到這個任務。 


       一個類似的麻煩事 FLAG_ACTIVITY_NEW_TASK 標誌。如果這個標誌導致activity啓動了一個新任務,並且用戶按下HOME鍵離開了它,必須有一些方法將用戶引導回它。一些實體(像是通知管理器) 總是在一個外部的任務中啓動activity,而不作爲它們的一部分,所以他們總是將帶有FLAG_ACTIVITY_NEW_TASK 標記的行爲對象傳遞到startActivity() 。如果你有一個可以被外部實體使用這個標籤調用的activity,要注意用戶應該有辦法返回到啓動的任務。 


    對於那些你不想讓用戶返回到activity的情況,將 <activity>的finishOnTaskLaunch屬性設置爲”true“,參看前面的 清理棧 一節。

官網:http://developer.android.com/guide/topics/manifest/activity-element.html#finish

裝載自:http://wdp107.iteye.com/blog/779215

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