Android Task Flag


回退棧(Back Stack):每個Task都存在一個BackStack,而系統中可以存在多個Task,但是每次只有一個Task獲得前臺焦點,一般而言,系統允許用戶在多個Task中切換,而被至於後臺的Task中的Activity,將被置於Stopped狀態。

Task 就像是一個 stack,一個一個的 activity 是構成 stack 的元素,做着入棧 (push) 和出棧 (pop-up)這樣簡單重複性的勞動.

Android的每個Activity都運行在堆棧中,一個Task棧可以有多個Activity,同一個Activity也可以在不同的Task棧中。

Task是分前臺和後臺的。一般當用戶啓動一個新的Task或者按Home鍵回到桌面時,當前Task就會被轉入後臺。如果用戶長時間離開某個Task,這個Task只保留root Activity,其他的都會被銷燬。

Activity的LaunchMode屬性可以指定Activity和Task之間的關係。

?
1
2
3
4
android:launchMode="standard"
android:launchMode="singleTop"
android:launchMode="singleTask"
android:launchMode="singleInstance"

系統默認是standard的,即同一個Activity可以被實例化多次。


1. Intent的setFlag和addFlag有什麼區別?

setFlag是把之前的替換掉,addFlag是添加新的

 有關的 Intent對象中設置的Flag標誌:


默認情況下,通過 startActivity() 啓動一個新的 Activity,新的 Activity 將會和調用者在同一個 stack 中。如果Intent 對象裏包含了 FLAG_ACTION_NEW_TASK,情況將發生變化,系統將爲新的 Activity “尋找”一個不同於調用者的 Task。不過要找的 Task 是不是一定就是 NEW 呢?如果是第一次執行,則這個設想成立;如果說不是第一次執行,也就是說已經有一個包含此 Activity 的Task 存在,則不會再啓動 Activity。



1 FLAG_ACTIVITY_BROUGHT_TO_FRONT 
    這個標誌一般不是由程序代碼設置的,如在launchMode中設置singleTask模式時系統幫你設定。

    //如果activity在task存在,拿到最頂端,不會啓動新的Activity

2 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。


3 FLAG_ACTIVITY_SINGLE_TOP,和singleTop對應

 如果設置,當這個Activity位於歷史stack的頂端運行時,不再啓動一個新的.

singleTop是指如果Task棧現在的順序是A,B,C,D。那麼如果現在傳來一個intent是啓動D的,那麼D是會調用onNewIntent來接受傳來的intent,而不會重新啓動D。所以Task棧的順序還是A,B,C,D。而不是A,B,C,D,D.

 singleTop的應用場景很多,一般適用於可以複用而又有多個開啓渠道的Activity,避免當一個Activity已經開啓並獲得焦點後,再次重複開啓。比如說Android系統瀏覽器的書籤頁面,就是一個singleTop模式的Activity。Android的瀏覽器是基於WebKit內核編寫的,它是支持JavaScript腳本語言的,可以通過JavaScript腳本設置瀏覽器書籤,這樣如果存在多個頁面存在保存書籤的JavaScript腳本,就會導致書籤頁面被多次開啓,所以書籤頁面被設置爲singleTop模式,這樣可以避免在保存多個書籤的時候重複開啓書籤頁面。

4 FLAG_ACTIVITY_NEW_TASK,和singleTask對應

如果設置該標誌,這個Activity會成爲歷史stack中一個新Task的開始。如果存在一個不同於當前調用者的Task(Task B),且該Task有目標Activity的存在,則切換到Task B中的Activity,執行Activity的onNewIntent方法。 


singleTask的的適用場景爲一般程序的主頁面,當回退到主頁面的時候,清除BackStack中,它之上的所有Activity,這樣避免程序導航邏輯的混亂。比如Android系統的瀏覽器的主頁面,就是singleTask模式的,上面提到,android下瀏覽器是Webkit內核的,它是由C語言編寫的,而每次打開新的網頁如果重新開啓一個Activity,是非常耗費系統資源的(需要解析HTML、Script腳本),所以被設置爲singleTask模式,這樣在瀏覽器應用裏,無論打開多少個頁面,使用的都是同一個Activity。所以以後如果存在很耗費系統資源的Activity,可以考慮使用singleTask開啓模式。


5 FLAG_ACTIVITY_MUTIPLE_TASK

    當設置該標誌時,新的Task總是會啓動來處理Intent,而不管這是是否已經有一個Task可以處理相同的事情。 
    由於默認的系統不包含圖形Task管理功能,因此,你不應該使用這個標誌,除非你提供給用戶一種方式可以返回到已經啓動的Task。 
    如果FLAG_ACTIVITY_NEW_TASK標誌沒有設置,這個標誌被忽略。


6 single instance

singleInstance是指Activity只能實例化一次並且獨佔一個Task。

被標記爲singleInstance啓動模式的Activity,在啓動的時候,會開啓一個新的BackStack,這個BackStack裏只有一個Activity的實例存在,並且把這個BackStack獲得焦點。這是一種很極端的模式,它會導致整個設備的操作系統裏,只會存在一個這個Activity示例,無論是從何處被啓動的。

   singleInstance一般適用於需要在系統中只存在一個實例的場景,比如Android系統的來電頁面,多次來電均使用的是一個Activity。






這些標誌有些是可以組合使用的,比如說clear top和single top同時用,則將目標Activity在Task棧上面的Activity都銷燬,並且將該intent傳遞給棧頂的Activity,此Activity可以回調onNewIntent方法.



part 2 : 系統開啓一個Task、BackStack、以及backstack清理,參考

1. start Activity

我們在開發一個應用程序的時候,需要指定應用程序的入口Activity,通過在AndroidManifest.xml清單文件中某個<Activity/>標籤內,使用<intent-filter/>標籤內指定。需要設置action爲"android.intent.action.MAIN",設置category爲"android.intent.category.LAUNCHER"。

這樣,當用戶點擊應用程序圖標之後,就會以這個入口Activity爲基礎,創建一個任務(Task),而這個Activity爲這個Task中的第一個Activity,稱爲根Activity。


2. task

Android中存在多個Task,但是同一時刻只有一個Task被置於前臺,其它的均爲後臺,而後臺的Task內的Activity,均爲Stopped狀態。Android系統中有多種方式切換Task,比如:按HOME鍵回到桌面、長按HOME鍵切換到其他Task等。而在同一個Task中,也只有BackStack最上面的Activity處於獲得焦點的狀態,其它也爲Stopped,每當系統需要把Activity置於Stopped時,都會自動在Bundle中保其內控件的狀態數據(需要爲控件設置ID標識),比如:控件輸入值、滾動條位置,以便下次獲得焦點的時候自動還原。


當系統資源不足的時候,如內存不足,會自動回收一些優先級比較低的組件的線程,以釋放資源給新的組件使用。那麼就存在問題了,當一個Task被切換到後臺之後,如果系統資源告急,自動銷燬了某個後臺Task中的Activity(除了根Activity外),當用戶再次切換回那個Task的時候,BackStack中存在這個Activity的標記,但是內存中已經不存在這個Activity的實例了,這個時候,系統就會通過Bundle來重新創建一個Activity用於還原它,這樣保證了用戶體驗,使用戶還是感覺在之前的頁面中操作。但是這種情況下,Bundle是不會保存之前Activity中的信息的,比如:控件輸入值、滾動條位置。這個時候,如果這個Activity的內容很重要的話,需要我們以編碼的方式去保存數據,並在重新創建的時候,以編碼的方式還原這個數據。

  以上兩種情況都需要用到兩個Activity的生命週期方法,onSaveInstanceState()和onRestoreInstanceState()。但是第一種情況是系統幫我們維護的,第二種特殊情況,需要開發人員編碼維護。下面是這兩個方法的簽名:

  • protected void onSaveInstanceState(Bundle outState):當Activity被系統回收的時候被調用 ,用這個方法保存Activity中需要保存的數據,存入outState參數即可。
  • protected void onRestoreInstanceState(Bundle savedInstanceState):當Activity被系統恢復的時候被調用,從Bundle中取出數據,設置會控件中,當然也可以通過重寫onCreate()方法來設置數據,因爲onCreate()一樣可以獲取到,但是推薦使用onRestoreInstanceState()。

3 back stack清理


在Android系統的清單文件中,不光爲我們提供了設置啓動模式的屬性android:LauncherMode,還爲我們提供了Activity的清理模式,有如下幾個:

  • android:alwaysRetainTaskState:這個屬性只對根Activity有效,默認爲false,當其設置爲true的時候,當這個根Activity失去焦點被置於後臺的時候,如不出現意外情況,其中的Activity將不會被系統回收。
  • android:clearTaskOnTask:這個屬性只對根Activity有效,當這個根Activity失去焦點被置於後臺的時候,會清理BackStack中根Activity之上的所有Activity,並在下次獲得焦點的時候顯示根Activity。
  • android:finishOnTaskLaunch:這個屬性只應用於單個Activity,它默認爲false,當其設置爲true的時候,當前Task如果在這個Activity獲得焦點的時候被切換到後臺,那麼這個Activity直接被銷燬,哪怕只是離開一小會兒。






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