Activity啟動模式 Tasks和Back Stack


 

Activity啟動模式 Tasks和Back Stack

 

  Task是用戶在進行某項工作時需要與之交互的一系列activities的集合。這些activities按照它們被打開的順序,被安放在一個堆棧里(back stack)。

  一個activity甚至可以打開其他應用的activity。

  比如你的應用需要發送一個電子郵件,你可以定義一個intent來執行發送動作,intent包含一些必要的數據,然后啟動另一個應用中的activity來執行發送郵件的動作,當郵件發送完,又回到你的activity。

  Android會將這兩個activity放在同一個task中來保持一致的用戶體驗。

 

Activity壓棧

  當前的activity啟動一個新的activity時,新的activity會被壓在back stack的棧頂並且獲得焦點。

  前一個activity仍然在棧中,但是stopped。

  當一個activity停止時,系統會保持它的用戶交互狀態。

  當用戶按下Back鍵,當前activity會出棧(這個activity會被銷毀),前一個activity會被恢復,並且它的UI狀態也會被恢復。

 

 

  當棧中的activities依次彈出,棧空了之后,task就不存在了。

 

Multitasking:Task在后台

  Task也只是一個有凝聚力的單元,當用戶開啟一個新的task,或者Home鍵回到桌面時,task將會變為在后台運行。

  當Task在后台時,其中所有的activity都是停止的,back stack保持不變,這個task只是失去了焦點。

  Task可以回到前台狀態,這樣用戶就可以回到他們離開的現場,即最頂端的activity會resume。

 

  后台中可以保持多個task,但是系統可能會kill后台的activity用來恢復內存,這樣就會導致activity的狀態丟失。

 

保存Activity狀態

  當activity停止時(stopped),系統的默認行為是保存它的狀態。

  然而,你可以,並且應該使用回調方法主動保留你的狀態,以防activity被系統kill而需要重建。

  當系統為了恢復內存而kill掉activity時,activity的狀態信息會丟失。

  但是系統仍然知道這個activity在back stack中的位置,當這個activity返回到棧頂時,系統會重建(recreate)它,而不是像之前一樣恢復它(resume)。

  所以為了不丟失用戶的工作,你需要實現 onSaveInstanceState() 方法來主動地保存數據。

 

管理Task

  Android系統是這樣管理task和back stack的:將activity按照啟動的順序壓入堆棧中,如果一個activity被啟動多次,會創建它的多個實例,然后將新的實例壓入棧中。

  如果你想介入並更改這種默認的行為也可以。

  比如你可能想在你的某一個activity啟動時新開啟一個task(而不是放在當前task中);

  又或者,當你啟動一個activity時,你希望把它的現有實例提到前面來(而不是在棧頂創建一個新的實例);

  或者,你希望在用戶離開你的task時清除除了根activity之外的所有activity。

 

  要做這些事,你可以通過manifest中 <activity>元素的屬性,還可以通過設置 startActivity()中傳遞的intent的flag來完成。

 

你可以使用的 <activity> 的屬性:

以及主要的intent的flag:

 

定義啟動模式

  啟動模式允許你定義一個新的activity實例是如何和當前task關聯的。

  你可以通過兩種方式來定義啟動模式:在manifest中定義或者通過用intent的flag。

  這里有兩點需要注意:

  1.有些啟動模式只能在manifest中定義,也有一些只能通過intent的flag定義。

  2.當一個activity A啟動一個activity B時,如果B在它的manifest中定義了啟動模式,但是A通過intent要求它用另一種啟動模式,以A的要求為主。

 

使用manifest file定義啟動模式

  可以在manifest文件中 <activity>標簽下使用 launchMode 屬性定義activity和task關聯的方式,它規定了activity如何啟動並進入一個task。

  注意,在manifest中定義的啟動模式可以被啟動activity的intent中的flag標明的模式覆蓋。

 

  有下面幾種屬性值:

"standard" (the default mode)

  默認模式。在當前task中,activity的新實例被創建,並且傳遞intent給它。一個activity可以被實例化多次,每個實例可以屬於不同的task,一個task也可以有多個它的實例。

"singleTop"

  如果當前task的頂部已經有一個這個activity的實例,系統就通過 onNewIntent() 方法向這個實例傳遞intent,而不是重新建立activity的實例。

  一個activity可以被實例化多次,並且實例可以屬於不同的task,一個task也可以有多個它的實例(頂部的activity不是這個activity的實例時,就會重新實例化)。

"singleTask"

  系統將會重新創建一個task並且實例化activity,將其放在task的根部。

  然而,如果這個activity的實例已經在一個單獨的task中存在,系統將會調用 onNewIntent() 方法將新的intent傳遞給這個已經存在的實例,而不是重新創建實例。

  在任一時刻,只能有一個這個activity的實例存在。

"singleInstance"

  和"singleTask"類似,唯一不同的是系統不會在這個activity的實例所在的task中啟動任何其他activity。

  這個activity的實例永遠是這個task中的唯一一個成員,這個activity啟動的任何其他activity都將在另外的task中打開。

 

返回處理

  不管activity是在一個新的task啟動還是當前task啟動,返回鍵永遠把用戶帶到之前的那個activity。

  但是有一種特殊情況:如果你啟動一個啟動模式為singleTask的activity,如果這個activity在一個后台task存在實例,那么這整個task將會被放到前台,這時候,back stack就會包含這個task中所有的activities,並且它們是放在棧頂。

  如下圖:

 

 

使用Intent的flag標明啟動模式

  通過設置傳遞給 startActivity()的intent的flag,可以修改要啟動的activity和它的task的關聯模式。

  可以使用的flags有:

FLAG_ACTIVITY_NEW_TASK

  和之前討論過的"singleTask"相同,在新的task中啟動activity,如果一個你需要的activity的task已經存在,則將它推向前台,恢復其上一個狀態,它通過onNewIntent()收到這個新的intent。

FLAG_ACTIVITY_SINGLE_TOP

  和"singleTop"行為相同,如果被啟動的activity是當前頂部的activity,則已經存在的實例收到 onNewIntent(),而不是新建實例。

FLAG_ACTIVITY_CLEAR_TOP

  如果被啟動的activity已經在當前task運行,不創建它的新實例,而是銷毀在它之上的其他所有activities,然后通過 onNewIntent()傳遞一個新的intent給這個恢復了的activity。

  這個行為在 launchMode 中沒有對應的屬性值。

  注意,如果activity的啟動模式是"standard",它自己也將被移除,然后一個新的實例將被啟動。

  這是因為當啟動模式是"standard"時,為了接收新的intent必須創建新的實例。

 

處理affinities

  Affinity指示了activity更傾向於屬於哪個task。

  默認情況下,同一個應用的activities傾向於在同一個task中。你可以通過<activity>標簽中的 taskAffinity來修改這種行為。

  詳細內容請查看:API Guides: Tasks and Back Stack

  http://developer.android.com/guide/components/tasks-and-back-stack.html

 

清理Back stack

  如果用戶離開一個task很久,系統就會清理這個task中的所有activities,除了根activity。當用戶返回到這個task,只有根activity會被恢復。

  

  有一些activity的屬性,你可以用來改變這一行為:

alwaysRetainTaskState

  如果這個屬性在task的根activity中被設置為true,那么上面描述的默認行為不會發生,即便過了很長時間,task仍將會保持所有的activities。

clearTaskOnLaunch

  如果這個屬性在task的根activity中被設置為true,每次用戶離開這個task,整個task都會被清到只剩根activity。

  這樣用戶永遠只能返回到它最初的狀態,即便離開的時間很短。

finishOnTaskLaunch

  這個屬性和上一個很像,但是它作用於單個activity,而不是整個task。

  它可以引起任何activity離開,包括根activity。

  當它被設置為true時,這個activity只在當前會話中屬於這個task,如果用戶離開再返回,它不會再出現。

 

開啟一個task

  你可以通過給activity一個intent filter(action是"android.intent.action.MAIN",category是"android.intent.category.LAUNCHER"),讓這個activity是一個task的進入點。

  如下:

 

<activity ... >
    <intent-filter ... >
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    ...
</activity>

 

  一個這樣的intent filter會使得這個activity的icon和label顯示在程序啟動處,提供了一種方法,使得用戶可以啟動這個activity,當它啟動后,用戶也可以通過它來返回到這個task。

  第二個能力是很重要的:用戶必須能夠離開一個task,然后通過activity launcher返回到它。

  因為這個原因,兩個讓activity永遠實例化一個task的啟動模式:"singleTask" 和"singleInstance",應該僅在activity有一個  ACTION_MAIN 和CATEGORY_LAUNCHER filter的時候用它們。

 

 

參考資料

  API Guides: Tasks and Back Stack

  http://developer.android.com/guide/components/tasks-and-back-stack.html

  <activity>標簽:

  http://developer.android.com/guide/topics/manifest/activity-element.html

  關於啟動模式,還可以參見博文:

  http://www.cnblogs.com/fanchangfa/archive/2012/08/25/2657012.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM