Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 剖析Activity管理棧

Android 剖析Activity管理棧

編輯:關於Android編程

activity棧一直以來總有點不清晰的感覺,今天就徹底的梳理一下。
在android中,一個activity組件可以激活另一個activity組件(可能屬於另一個應用程序)。

若新的被激活的activity組件屬於另一個應用程序,則那個activity組件會運行在那個應用程序的進程中,但是從用戶的角度來看,好像就是屬於本應用程序一樣。Android是通過將之前的activity組件和新被激活的activity組件放入同一個任務棧來實現這個功能的。從用戶的角度看,一個任務棧就代表了“一個應用程序”。它實際上是一個棧,裡面放著一組被排列好的相關的activity組件。位於棧底的activity(根activity)就是開啟這個任務棧的activity組件,一般情況下,就是應用程序的主界面。而位於棧頂的activity組件即代表當前被激活的activity組件(可接收用戶行為的activity)。

任務棧中包含了activity組件的對象,且任務棧中可以包含有某一個activity組件類型的多個實例對象。在任務棧中的activity組件不能被重排序,只能被壓棧和彈棧。

任務棧不是某個類型,也不是某一個元素,它是一組activity組件的組織形式。所以沒有辦法在不影響任務棧中的activity組件的情況下,單獨設置任務棧的參數。根activity的參數既是整個任務棧的參數,它會影響任務棧中的所有activity組件。

當某個應用程序在前後台切換的時候,實際上就是代表這個應用程序的一個任務棧在前後台切換。

剛剛描述的行為是activity和任務棧的默認行為,但也有辦法在很多方面對它進行修改:

方法1:在發送的請求(即Intent對象)中設置一些標記。

方法2:在manifest文件中,對接收請求(即Intent對象)的activity組件設置一些屬性。

所以在請求者和接收者中都可以進行控制。

在Intent對象中主要的標志有:

FLAG_ACTIVITY_NEW_TASK

FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

FLAG_ACTIVITY_SINGLE_TOP

標簽中,主要的屬性有:

taskAffinity android:taskAffinity=”com.cardroid.sdhc” 表示兩個應用裡面的親屬關系,如果一個應用的某個ACTIVITY和另一個應用的ACTIVITY設置這個屬性
然後,這兩個ACTIVITY顯示後點擊HOME鍵盤,從一個應用啟動就會顯示點擊HOME的那個ACTIVITY

launchMode 

allowTaskReparenting 

clearTaskOnLaunch 

alwaysRetainTaskState 

finishOnTaskLaunch

接下來的內容就會講解一些Intent標志和標簽屬性的作用和用法。

1.親屬關系和新的任務

默認情況下,一個應用程序中的activity組件彼此之間是親屬關系――也就是說它們屬於同一個任務棧。但是我們可以通過設置某個標簽的taskAffinity屬性來為這個activity組件設置親屬關系。在不同的應用程序中定義的activity組件可以共用同一個親屬關系,或者在同一個的應用程序中定義的activity組件可以使用不同的親屬關系。親屬關系會在兩種情況下發揮作用:

1)負責激活activity組件的Intent對象中包含了FLAG_ACTIVITY_NEW_TASK標志。

2)被激活的activity組件的allowTaskReparenting屬性被設置為“true”。

問題:

在同一個程序中,不同的Activity設置了相同的(默認)或不同的taskAffinity屬性,那麼在默認標志和FLAG_ACTIVITY_NEW_TASK時,會如何跳轉?共有4中組合。

在跨程序啟動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組件指定不同的親屬關系。

2.啟動模式

標簽的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”模式,可以有多個實例,並且這些實例可以屬於不同的任務棧,每個任務棧也可以包含有這個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對象會被丟棄。(雖然會被丟棄,但是這個intent對象會使這個任務棧切換到前台)

如果一個新到達的intent對象是被一個已經存在的activity組件來處理的,那麼這個activity的onNewIntent(android.content.Intent)方法會被系統調用。

注意:若為了處理一個新到達的intent對象而創建了一個activity實例,則用戶按下“BACK”鍵就會退到之前的那個activity。但若這個新到達的intent對象是由一個已經存在的activity組件來處理的,那麼用戶按下“BACK” 鍵就不會回退到處理這個新intent對象之前的狀態了

3.清理任務棧

如果一個任務棧在很長的一段時間都被用戶保持在後台的,那麼系統就會將這個任務棧中除了根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類型的實例,並且讓此實例位於棧頂。

4.啟動任務棧

通過將一個activity類型的intent-filter的動作設置為“android.intent.action.MAIN”,類別設置為“android.intent.category.LAUNCHER”可以使這個activity實例稱為一個任務棧的入口。擁有這種類型的intent-filter的activity類型的圖表和名字也會顯示在application launcher中。

第二個能力是很重要的:用戶必須能夠使一個任務棧切換到後台,也可以隨時將其切換到前台。出於這個原因,使activity在啟動時新開任務棧的啟動模式(即“singleTask”和“singleInstance”模式)只應該被利用在擁有擁有“android.intent.action.MAIN”動作和“android.intent.category.LAUNCHER”類別的intent-filter的activity類型上。

類似的限制同樣體現在FLAG_ACTIVITY_NEW_TASK標志上。如果這個標志使一個activity開始了一個新的任務棧,並且用戶點擊“HOME”鍵將其切換到了後台,則必須有某種方式使用戶可以重新將那個任務棧切換到前台。一些實例(比如通知管理器),總是在外部的任務棧中開啟一個activity,而不是其自身的任務棧,所以它們總是將FLAG_ACTIVITY_NEW_TASK標志放入Intent對象中,並將Intent對象傳入startActivity()方法中。
對於在某些情況下,你不希望用戶能夠返回到某一個activity,那麼可以通過設置標簽的“finishOnTaskLaunch”屬性為“true”來實現。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved