天天看點

Activity堆棧管理

task就好像是能包含很多activity的棧。 預設情況下,一個activity啟動另外一個activity時,兩個activity是放在同一個task棧中的,第二個activity壓入第一個 activity所在的task棧。當使用者按下傳回鍵時,第二個activity從棧中彈出,第一個activity又在目前螢幕顯示。這樣,從使用者角度來看,這兩個activity就好像是屬于同一個應用程式的,即使第二個activity是屬于另外一個應用程式的。當然,這是指預設情況下。 task棧包含的是activity的對象。如果一個activity有多個執行個體在運作,那麼棧中儲存的是每個執行個體的實體。棧中的activity不會重新排列,隻有彈出和壓入操作。

一個task中的所有activity都以整體的形式移動。整個task可以被移到前台或背景。打個比方,目前的task包含4個activity–目前 activity下面有3個activity。當使用者按下home鍵傳回到程式啟動器(application launcher)後,選擇了一個新的應用程式(事實上是一個新的task),目前的task就被轉移到背景,新的task中的根activity将被顯示在螢幕上。過了一段時間,使用者按傳回鍵回到了程式啟動器界面,選擇了之前運作的程式(之前的task)。那個task,仍然包含着4個

activity。當使用者再次按下傳回鍵時,螢幕不會顯示之前留下的那個activity(之前的task的根activity),而顯示目前 activity從task棧中移出後棧頂的那個activity。 剛剛描述的行為是預設的activity和task的行為。有很多方法能夠改變這種行為。activity和task之間的聯系,以及task中的 activity的行為可以通過intent中的标記 以及在manifest中的<activity>元素的屬性 控制。其中,主要的intent标記有:

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都有一個affinity–這讓它們屬性同一個task。然而,每個activity可以通過<activity>中的taskaffinity屬性設定單獨的affinity。不同應用程式中的activity可以共享同一個 affinity,同一個應用程式中的不同activity也可以設定成不同的affinity。affinity屬性在2種情況下起作用:當啟動 activity的intent對象包含flag_activity_new_task标記,或當activity的

allowtaskreparenting被設定成true。flag_activity_new_task 标記

當傳遞給startactivity()的intent對象包含 flag_activity_new_task标記時,系統會為需要啟動的activity尋找與目前activity不同的task。如果要啟動的 activity的affinity屬性與目前所有的task的affinity屬性都不相同,系統會建立一個帶那個affinity屬性的task,并将要啟動的activity壓到建立的task棧中;否則将activity壓入那個affinity屬性相同的棧中。

allowtaskreparenting屬性

如果一個activity的allowtaskreparenting屬性為true,那麼它可以從一個task(task1)移到另外一個有相同affinity的task(task2)中(task2帶到前台時)。

如果一個.apk檔案從使用者角度來看包含了多個“應用程式”,你可能需要對那些 activity賦不同的affinity值。

activity的launchmode屬性可以有四種值:

“<code>standard</code> ” (預設)

“<code>singletop</code> “

“<code>singletask</code> “

“<code>singleinstance</code> “

這4種模式可以按4種分類來區分,以下假設位于task1中的activity1啟動activity2:

模式/分類

包容activity2的task

一個activity是否允許有多個執行個體

activity是否允許有其它activity共存于一個task

對于新的intent,是否總是執行個體化activity對象

standard

如果不包含flag_activity_new_task标記,則activity2放入 task1,否則按前面講述的規則為activity2選擇task

可被多次執行個體化,同一個task的不同的執行個體可位于不同的task中,每個task也可包含多個執行個體

允許

是的。當接收到新的intent時,總是會生成新的activity對象。

singletop

同standard

已存在的activity對象,如果位于目标task的棧頂,則該activity被重用,如果它不位于棧頂,則會執行個體化新的activity對象

singletask

将activity2放到task1棧底

不能有多個執行個體。由于該模式下activity總是位于棧頂,是以actvity在同一個裝置裡至多隻有一個執行個體

允許。singletask模式的activity總是位于棧底位置。目标activity 執行個體已存在時,如果該執行個體剛好位于task棧頂,則接收intent,否則到來的intent将會被丢棄,但該可以響應該intent的那個 activity所在的task将會被移到前台。

singleinstance

同singletask

不允許與其它activity共存于一個task。如果activity1的運作在該模式下,則activity2一定與activity1位于不同的task

對于新到的intent,如果是由新建立的activity對象來接收,則使用者可以通過傳回鍵回到之前的activity;如果是由已存在的 activity來接收,則使用者無法通過傳回鍵傳回到接收intent之前的狀态。

當使用者長時間離開task(目前task被轉移到背景)時,系統會清除task中棧底activity外的所有activity。這樣,當使用者傳回到task時,隻留下那個task最初始的activity了。

這是預設的情況,&lt;activity&gt;中有些屬性可以改變這種行為。

alwaysretaintaskstate屬性

如果棧底activity的這個屬性被設定為true,剛剛描述的情況就不會發生。 task中的所有activity将被長時間儲存。

cleartaskonlaunch屬性

如果棧底activity的這個屬性被設定為true,一旦使用者離開task,則 task棧中的activity将被清空到隻剩下棧底activity。這種情況剛好與alwaysretaintaskstate相反。即使使用者隻是短暫地離開,task也會傳回到初始狀态(隻剩下棧底acitivty)。

finishontasklaunch屬性

這個屬性與cleartaskonlaunch相似,但它隻對單獨的activity操作,而不是整個task。它可以結束任何activity,包括棧底的activity。當它設定為true時,目前的activity隻在目前會話期間作為task的一部分存在,當使用者退出activity再傳回時,它将不存在。

另外還有一種方法能将activity強行從stack中移出。如果intent對象包含flag_activity_clear_top 标記,當目标task中已存在與接收該intent對象的 activity類型相同的activity執行個體存在時,所有位于該activity對象上面的activity将被清空,這樣接收該intent的 activity就位于棧頂,可以響應到來的intent對象。如果目标activity的運作模式為standard,則目标activtiy也會被清空。因為當運作模式為standard時,總會建立新的activity對象來接收到來的intent對象。

flag_activity_clear_top标記常常和flag_activity_new_task一起使用。用2個标記可以定位已存在的 activity并讓它處于可以響應intent的位置。

intent filter中有”<code>android.intent.action.main</code> ” action和”<code>android.intent.category.launcher</code> ”

category的activity将被标記為task的入口。帶有這兩個标記的activity将會顯示在應用程式啟動器(application launcher)中。

第二個比較重要的點是,使用者必須能夠離開task并在之後傳回。因為這個原因,singletask和singleinstance這兩種運作模式隻能應用于含有main和launcher過濾器的 activity 。打個比方,如果不包含帶main和launcher過濾器,某個activity運作了一個singletask模式的 activity,初始化了一個新的task,當使用者按下home鍵時,那個activity就被主螢幕“擋住”了,使用者再也無法傳回到那個

activity。

類似的情況在flag_activity_new_task标記上也會出現。如果這個标記會建立一個task,當使用者按下home鍵時,必須有一種方式能夠讓使用者傳回到那個activity。有些東西(比如notification manager)總是要求在外部task中啟動activity,在傳遞給startactivity的intent中總是包含 flag_activity_new_task标記。

對于那種不希望使用者離開之後再傳回activity的情況,可将finishontasklaunch屬性設定為true。