Activity的4種加載模式最佳解答及Intent常用標識
Activity的4種狀態:
活動的:當一個Activity在棧頂,它是可視的、有焦點、可接受用戶輸入的。Android試圖盡最大可能保持它活動狀態,殺死其它Activity來確保當前活動Activity有足夠的資源可使用。當另外一個Activity被激活,這個將會被暫停。
暫停:在很多情況下,你的Activity可視但是它沒有焦點,換句話說它被暫停了。有可能原因是一個透明或者非全屏的Activity被激活。
當被暫停,一個Activity仍會當成活動狀態,只不過是不可以接受用戶輸入。在極特殊的情況下,Android將會殺死一個暫停的Activity來為活動的Activity提供充足的資源。當一個Activity變為完全隱藏,它將會變成停止。
停止:當一個Activity不是可視的,它“停止”了。這個Activity將仍然在內存中保存它所有的狀態和會員信息。盡管如此,當其它地方需要內存時,它將是最有可能被釋放資源的。當一個Activity停止后,一個很重要的步驟是要保存數據和當前UI狀態。一旦一個Activity退出或關閉了,它將變為待用狀態。
待用: 在一個Activity被殺死后和被裝在前,它是待用狀態的。待用Acitivity被移除Activity棧,并且需要在顯示和可用之前重新啟動它。
Activity的4種加載模式:
在android的多activity開發中,activity之間的跳轉可能需要有多種方式,有時是普通的生成一個新實例,有時希望跳轉到原來某個activity實例,而不是生成大量的重復的activity。加載模式便是決定以哪種方式啟動一個跳轉到原來某個Activity實例。
在android里,有4種activity的啟動模式,分別為:
standard: 標準模式,一調用startActivity()方法就會產生一個新的實例。
singleTop: 來了intent, 每次都創建新的實例,僅一個例外:當棧頂的activity 恰恰就是該activity的實例(即需要創建的實例)時,不再創建新實例。這解決了棧頂復用問題
singleTask: 來了intent后,檢查棧中是否存在該activity的實例,如果存在就把intent發送給它,否則就創建一個新的該activity的實例,放入一個新的task棧的棧底。肯定位于一個task的棧底,而且棧中只能有它一個該activity實例,但允許其他activity加入該棧。解決了在一個task中共享一個activity。
singleInstance: 這個跟singleTask基本上是一樣,只有一個區別:在這個模式下的Activity實例所處的task中,只能有這個activity實例,不能有其他的實例。一旦該模式的activity的實例已經存在于某個棧中,任何應用在激活該activity時都會重用該棧中的實例,解決了多個task共享一個activity。
這些啟動模式可以在功能清單文件AndroidManifest.xml中進行設置,中的launchMode屬性。
如果是從BroadcastReceiver啟動一個新的Activity,或者是從Service往Activity跳轉時,要將Intent的Flag設置為FLAG_ACTIVITY_NEW_TASK才可以
影響加載模式的一些特性:
核心的Intent Flag有:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
核心的特性有:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
Activity在Activity棧(Task)中的加載順序是可以控制的,這就需要用到Intent Flag
Intent常用標識:
FLAG_ACTIVITY_BROUGHT_TO_FRONT
這個標志一般不是由程序代碼設置的,如在launchMode中設置singleTask模式時系統幫你設定。
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。
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
如果設置,這將在Task的Activity stack中設置一個還原點,當Task恢復時,需要清理Activity。也就是說,下一次Task帶著 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED標記進入前臺時(典型的操作是用戶在主畫面重啟它),這個Activity和它之上的都將關閉,以至于用戶不能再返回到它們,但是可以回到之前的Activity。
這在你的程序有分割點的時候很有用。例如,一個e-mail應用程序可能有一個操作是查看一個附件,需要啟動圖片瀏覽Activity來顯示。這個 Activity應該作為e-mail應用程序Task的一部分,因為這是用戶在這個Task中觸發的操作。然而,當用戶離開這個Task,然后從主畫面選擇e-mail app,我們可能希望回到查看的會話中,但不是查看圖片附件,因為這讓人困惑。通過在啟動圖片瀏覽時設定這個標志,瀏覽及其它啟動的Activity在下次用戶返回到mail程序時都將全部清除。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果設置,新的Activity不會在最近啟動的Activity的列表中保存。
FLAG_ACTIVITY_FORWARD_RESULT
如果設置,并且這個Intent用于從一個存在的Activity啟動一個新的Activity,那么,這個作為答復目標的Activity將會傳到這個新的Activity中。這種方式下,新的Activity可以調用setResult(int),并且這個結果值將發送給那個作為答復目標的 Activity。
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
這個標志一般不由應用程序代碼設置,如果這個Activity是從歷史記錄里啟動的(常按HOME鍵),那么,系統會幫你設定。
FLAG_ACTIVITY_MULTIPLE_TASK
不要使用這個標志,除非你自己實現了應用程序啟動器。與FLAG_ACTIVITY_NEW_TASK結合起來使用,可以禁用把已存的Task送入前臺的行為。當設置時,新的Task總是會啟動來處理Intent,而不管這是是否已經有一個Task可以處理相同的事情。
由于默認的系統不包含圖形Task管理功能,因此,你不應該使用這個標志,除非你提供給用戶一種方式可以返回到已經啟動的Task。
如果FLAG_ACTIVITY_NEW_TASK標志沒有設置,這個標志被忽略。
FLAG_ACTIVITY_NEW_TASK
如果設置,這個Activity會成為歷史stack中一個新Task的開始。一個Task(從啟動它的Activity到下一個Task中的 Activity)定義了用戶可以遷移的Activity原子組。Task可以移動到前臺和后臺;在某個特定Task中的所有Activity總是保持相同的次序。
這個標志一般用于呈現“啟動”類型的行為:它們提供用戶一系列可以單獨完成的事情,與啟動它們的Activity完全無關。
使用這個標志,如果正在啟動的Activity的Task已經在運行的話,那么,新的Activity將不會啟動;代替的,當前Task會簡單的移入前臺。參考FLAG_ACTIVITY_MULTIPLE_TASK標志,可以禁用這一行為。
這個標志不能用于調用方對已經啟動的Activity請求結果。
FLAG_ACTIVITY_NO_ANIMATION
如果在Intent中設置,并傳遞給Context.startActivity()的話,這個標志將阻止系統進入下一個Activity時應用 Acitivity遷移動畫。這并不意味著動畫將永不運行——如果另一個Activity在啟動顯示之前,沒有指定這個標志,那么,動畫將被應用。這個標志可以很好的用于執行一連串的操作,而動畫被看作是更高一級的事件的驅動。
FLAG_ACTIVITY_NO_HISTORY
如果設置,新的Activity將不再歷史stack中保留。用戶一離開它,這個Activity就關閉了。這也可以通過設置noHistory特性。
FLAG_ACTIVITY_NO_USER_ACTION
如果設置,作為新啟動的Activity進入前臺時,這個標志將在Activity暫停之前阻止從最前方的Activity回調的onUserLeaveHint()。
典型的,一個Activity可以依賴這個回調指明顯式的用戶動作引起的Activity移出后臺。這個回調在Activity的生命周期中標記一個合適的點,并關閉一些Notification。
如果一個Activity通過非用戶驅動的事件,如來電或鬧鐘,啟動的,這個標志也應該傳遞給Context.startActivity,保證暫停的Activity不認為用戶已經知曉其Notification。
FLAG_ACTIVITY_PREVIOUS_IS_TOP
If set and this intent is being used to launch a new activity from an existing one, the current activity will not be counted as the top activity for deciding whether the new intent should be delivered to the top instead of starting a new one. The previous activity will be used as the top, with the assumption being that the current activity will finish itself immediately.
FLAG_ACTIVITY_REORDER_TO_FRONT
如果在Intent中設置,并傳遞給Context.startActivity(),這個標志將引發已經運行的Activity移動到歷史stack的頂端。
例如,假設一個Task由四個Activity組成:A,B,C,D。如果D調用startActivity()來啟動Activity B,那么,B會移動到歷史stack的頂端,現在的次序變成A,C,D,B。如果FLAG_ACTIVITY_CLEAR_TOP標志也設置的話,那么這個標志將被忽略。
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
If set, and this activity is either being started in a new task or bringing to the top an existing task, then it will be launched as the front door of the task. This will result in the application of any affinities needed to have that task in the proper state (either moving activities to or from it), or simply resetting that task to its initial state if needed.
FLAG_ACTIVITY_SINGLE_TOP
如果設置,當這個Activity位于歷史stack的頂端運行時,不再啟動一個新的。
注意:如果是從BroadcastReceiver啟動一個新的Activity,或者是從Service往一個Activity跳轉時,不要忘記添加Intent的Flag為FLAG_ACTIVITY_NEW_TASK。