在android中。一個activity組件能夠激活還有一個activity組件:本程序activity和其他程序的activity。
若新的被激活的activity組件屬於還有一個應用程序,則那個activity組件會執行在那個應用程序的進程中,可是從用戶的角度來看,好像就是屬於本應用程序一樣。Android是通過將之前的activity組件和新被激活的activity組件放入同一個任務棧來實現這個功能的。從用戶的角度看,一個任務棧就代表了“一個應用程序”。它實際上是一個棧,里面放着一組被排列好的相關的activity組件。
位於棧底的activity(根activity)就是開啟這個任務棧的activity組件,普通情況下,就是應用程序的主界面。而位於棧頂的activity組件即代表當前被激活的activity組件(可接收用戶行為的activity)。
任務棧中包括了activity組件的對象,且任務棧中能夠包括有某一個activity組件類型的多個實例對象。在任務棧中的activity組件不能被重排序。僅僅能被壓棧和彈棧。
任務棧不是某個類型。也不是某一個元素,它是一組activity組件的組織形式。所以沒有辦法在不影響任務棧中的activity組件的情況下。單獨設置任務棧的參數。根activity的參數既是整個任務棧的參數。它會影響任務棧中的全部activity組件。
當某個應用程序在前后台切換的時候,實際上就是代表這個應用程序的一個任務棧在前后台切換。
剛剛描寫敘述的行為是activity和任務棧的默認行為,但也有辦法在非常多方面對它進行改動:
1.taskAffinity和allowTaskReparenting使用
方法1:在發送的請求(即Intent對象)中設置一些標記。
方法2:在manifest文件里。對接收請求(即Intent對象)的activity組件設置一些屬性。
所以在請求者和接收者中都能夠進行控制。
在Intent對象中基本的標志有:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_SINGLE_TOP
在<activity>標簽中。基本的屬性有:
taskAffinity android:taskAffinity="com.cardroid.sdhc" 表示兩個應用里面的親屬關系,假設一個應用的某個Application1中的ActivityL1和還有一個應用的Application2中的ActivityR1設置這個屬性,當中ActivityL1的allowTaskReparenting=true同意任務棧動態載入。
然后,ActivityL1顯示后點擊HOME鍵盤,從還有一個應用ActivityR1啟動后就會顯示點擊HOME的那個ActivityL1在前台,由於ActivityL1為動態任務棧載入。同一時候由於taskAffinity的存在,所以增加到了ActivityR1任務棧中,並顯示在前台。
接下來的內容就會解說一些Intent標志和<activity>標簽屬性的作用和使用方法。
allowTaskReparenting
launchMode
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
2.親屬關系和新的任務
默認情況下,一個應用程序中的activity組件彼此之間是親屬關系――也就是說它們屬於同一個任務棧。可是我們能夠通過設置某個<activity>標簽的taskAffinity屬性來為這個activity組件設置親屬關系。在不同的應用程序中定義的activity組件能夠共用同一個親屬關系,或者在同一個的應用程序中定義的activity組件能夠使用不同的親屬關系。每一個Activity都有taskAffinity屬性。這個屬性指出了它希望進入的Task。
假設一個Activity沒有顯式的指明該 Activity的taskAffinity,那么它的這個屬性就等於Application指明的taskAffinity。假設 Application也沒有指明,那么該taskAffinity的值就等於包名。
而Task也有自己的affinity屬性,它的值等於它的根 Activity的taskAffinity的值。
一開始,創建的Activity都會在創建它的Task中,而且大部分都在這里度過了它的整個生命。然而有一些情況。創建的Activity會被分配其他的Task中去,有的甚至,本來在一個Task中,之后出現了轉移。親屬關系會在兩種情況下發揮作用:
1)負責激活activity組件的Intent對象中包括了FLAG_ACTIVITY_NEW_TASK標志。
2)被激活的activity組件的allowTaskReparenting屬性被設置為“true”。
問題:
1.在同一個程序中。不同的Activity設置了同樣的(默認)或不同的taskAffinity屬性,那么在默認標志和FLAG_ACTIVITY_NEW_TASK時,會怎樣跳轉?共同擁有4中組合。
2.在跨程序啟動Activity時。不同的Activity設置了同樣的或不同的(默認)taskAffinity屬性。那么在默認標志和FLAG_ACTIVITY_NEW_TASK時,會怎樣跳轉?共同擁有4中組合。
關於FLAG_ACTIVITY_NEW_TASK標志量
默認情況下。一個被激活的新activity會和負責激活它的那個activity組件存在於同一個任務棧中。可是若負責激活的Intent對象包括了FLAG_ACTIVITY_NEW_TASK標志,則系統會為存放那個即被激活的新activity尋找一個新的任務棧。
此時,若已經存在了同樣親屬關系的任務棧,則系統會直接將這個即被激活的新activity放入到這個任務棧中。否則系統會開始一個新的任務棧。
關於allowTaskReparenting屬性
若一個activity組件的allowTaskReparenting被置為“true”。則當與這個activity有同樣的親屬關系的任務棧被切換到前台的時候,這個activity會從當前存在的任務棧中移動到與其有同樣的親屬關系的任務棧中。
若從用戶的角度來看,一個.apk文件包括了一個以上的“應用程序”,那你可能要為那些activity組件指定不同的親屬關系。
3.啟動模式
<activity>標簽的launchMode屬性能夠設置為四種不同的模式:“standard”(默認模式)
“singleTop”
android:launchMode="singleTop" 相當於每次都從這個ACITIVITY啟動
“singleTask”
android:launchMode="singleTop" 和singleTop類似,不同於,每次啟動后都在最上面
“singleInstance”
這幾種模式的差別體現下面四點上:
1)當這個activity被激活的時候,會放入哪個任務棧。
對於“standard”和“singleTop”模式。這個新被激活的activity會放入和之前的activity同樣的任務棧中――除非如前所述,Intent對象包括FLAG_ACTIVITY_NEW_TASK標志。
但“singleTask”和“singleInstance”模式則表示這個新被激活的activity不會放入已經存在的任務棧中,它會又一次開啟一個任務棧,並作為這個新的任務棧的根activity。
2)能否夠存在這個activity類型的多個實例。
對於“standard”和“singleTop”模式。能夠有多個實例。而且這些實例能夠屬於不同的任務棧,每一個任務棧Task也能夠包括有這個activity類型的多個實例。
但“singleTask”和“singleInstance”模式則表示至多僅僅能夠存在這個activity類型的一個實例。
而且這一點必須是根activity的限制,一個任務中僅僅能被實例化一次。所以這意味着在同一時間。在手機上絕不會存在多於一個的由這個activity啟動的任務棧。
3)包括此activity的任務棧能否夠包括其他的activity。
“singleInstance”模式表示包括此activity的任務棧不能夠包括其他的activity。若此activity啟動了還有一個activity組件,那么不管那個activity組件的啟動模式是什么或是Intent對象中是否包括了FLAG_ACTIVITY_NEW_TASK標志,它都會被放入另外的任務棧。在其他方面“singleInstance”模式和“singleTask”模式是一樣的。
其余三種啟動模式則同意包括此activity的任務棧包括其他的activity。
4)Whether a new instance of the class will be launched to handle a new intent.
對於默認的“standard”模式,每當響應一個Intent對象。都會創建一個這樣的activity類型的新的實例。
即每個activity實例處理一個intent。
對於“singleTop”模式,僅僅有當這個activity的實例當前處於任務棧的棧頂位置。則它會被反復利用來處理新到達的intent對象。
否則就和“standard”模式的行為一樣。
正如第二點所說的,“singleTask”和“singleInstance”模式表示僅僅能有一個實例,所以這個唯一的實例須要處理全部新到達的intent對象。又因為“singleInstance”模式的activity實例總是位於任務棧的棧頂,所以這樣做非常正常。
但對於“singleTask”模式的acitvity,假設發給該Activity的Intent對象到來時該Activity不在堆棧頂端。那么該Intent對象將被丟棄,可是界面還是會切換到當前的Activity。
(盡管會被丟棄,可是這個intent對象會使這個任務棧切換到前台)
假設一個新到達的intent對象是被一個已經存在的activity組件來處理的,那么這個activity的on
注意:若為了處理一個新到達的intent對象而創建了一個activity實例。則用戶按下“BACK”鍵就會退到之前的那個activity。但若這個新到達的intent對象是由一個已經存在的activity組件來處理的。那么用戶按下“BACK” 鍵就不會回退到處理這個新intent對象之前的狀態了。
4.清理任務棧
假設一個任務棧在非常長的一段時間都被用戶保持在后台的。那么系統就會將這個任務棧中除了根activity以外的其他所有activity所有清除掉。從這之后,當用戶再將任務棧切換到前台,則僅僅能顯示根activity了。
以上說的是默認模式。能夠通過<activity>標簽的一些屬性來更改:
1)alwaysRetainTaskState屬性
假設將根activity的alwaysRetainTaskState屬性設置為“true”,則即便一個任務棧在非常長的一段時間都被用戶保持在后台的。系統也不會對這個任務棧進行清理。
2)clearTaskOnLaunch屬性
假設將根activity的clearTaskOnLaunch屬性設置為“true”。那么僅僅有這個任務棧切換到了后台。那么系統就會將這個任務棧中除了根activity以外的其他所有activity所有清除掉。即和alwaysRetainTaskState的行為全然相反。
3) finishOnTaskLaunch屬性
這個屬性的行為類似於clearTaskOnLaunch,可是此屬性作用於單個的activity對象,而不是整個任務棧。
當這個任務棧切換到了后台,這個屬性能夠使任務棧清理包含根activity在內的不論什么activity對象。
這里也有還有一種方法來使activity對象從任務棧中被移除。
若Intent對象包括FLAG_ACTIVITY_CLEAR_TOP標志。而且在目標任務棧中已經存在了用於處理這個Intent對象的activity類型的一個實例,那么在任務棧中這個實例之上的全部activity實例會被移除。從而用於處理這個Intent對象的activity類型的那個實例會位於任務棧的棧頂。並用來處理那個Intent對象。若那個匹合的activity類型的啟動模式是“standard”,則這個已經存在於任務棧中的匹合的activity類型的實例也會被移除,而且一個新的此類型activity的實例被創建並壓棧來處理這個Intent對象。
FLAG_ACTIVITY_CLEAR_TOP這個標志常常和FLAG_ACTIVITY_NEW_TASK標志結合使用。這樣結合使用的意思是在還有一個任務棧中定位已經存在的匹合的activity類型的實例,而且讓此實例位於棧頂。
5.啟動任務棧
通過將一個activity類型的intent-filter的動作設置為“android.intent.act第二個能力是非常重要的:用戶必須可以使一個任務棧切換到后台,也可以隨時將其切換到前台。出於這個原因,使activity在啟動時新開任務棧的啟動模式(即“singleTask”和“singleInstance”模式)僅僅應該被利用在擁有擁有“android.intent.act
類似的限制相同體如今FLAG_ACTIVITY_NEW_TASK標志上。
假設這個標志使一個activity開始了一個新的任務棧,而且用戶點擊“HOME”鍵將其切換到了后台。則必須有某種方式使用戶能夠又一次將那個任務棧切換到前台。一些實例(比方通知管理器),總是在外部的任務棧中開啟一個activity,而不是其自身的任務棧,所以它們總是將FLAG_ACTIVITY_NEW_TASK標志放入Intent對象中,並將Intent對象傳入startActivity()方法中。
對於在某些情況下,你不希望用戶可以返回到某一個activity。那么可以通過設置<activity>標簽的“finishOnTaskLaunch”屬性為“true”來實現。
參考: