閱讀678 返回首頁    go 人物


activity的啟動模式和棧管理

 在學習Android的過程中,Intent是我們最常用Android用於進程內或進程間通信的機製,其底層的通信是以Binder機製實現的,在物理層則是通過共享內存的方式實現的。
    Intent主要用於2種情景下:(1)發起意圖  (2)廣播
    它的屬性有:ComponentName,action,data,category,extras,flags等,通常情況下,進行Intent的匹配涉及到3個屬性:Action,Data,Category。這些東西都需要了解才能對它有個深入的體會。
    下麵我就根據近期學習,總結記錄下Activity啟動模式 及 Intent Flags 與 棧 的關聯分析。


文章結構:

1.什麼是棧
2.Activity棧
3.Task
4.Activity啟動模式
5.Activity棧和Task聯係
6.Intent Flags 
7.Activity相關屬性taskAffinity

1.什麼是棧


<span >棧是一種常用的數據結構,棧隻允許訪問棧頂的元素,棧就像一個杯子,每次都隻能取杯子頂上的東西,而對於棧就隻能每次訪問它的棧頂元素,從而可以達到保護棧頂元素以下的其他元素.”先進後出”或”後進先出”就是棧的一大特點,先進棧的元素總是要等到後進棧的元素出棧以後才能出棧.遞歸就是利用到了係統棧,暫時保存臨時結果,對臨時結果進行保護.</span>
<span >
</span>
<h2 ><a target=_blank name="t2"></a><span >定義棧(Stack)</span></h2><span ><strong>棧的定義棧(Stack)是限製僅在表的一端進行插入和刪除運算的線性表。(1)通常稱插入、刪除的這一端為棧頂(Top),另一端稱為棧底(Bottom)。 (2)當表中沒有元素時稱為空棧。(3)棧為後進先出(Last In First Out)的線性表,簡稱為LIFO表。棧的修改是按後進先出的原則進行。每次刪除(退棧)的總是當前棧中"最新"的元素,即最後插入(進棧)的元素,而最先插入的是被放在棧的底部,要到最後才能刪除。</strong></span>
<span ><span ><strong>
</strong></span></span><h2 ><a target=_blank name="t3"></a><span >棧的操作</span><span >:壓棧、彈棧 </span></h2><div >
</div><h1><a target=_blank name="t4"></a><span >2.Activity中的棧</span></h1><div><span >
</span></div>
Android的管理主要是通過Activity棧來進行,當一個Activity啟動時,係統會根據其配置將它壓入到一個特定的棧中,係統處於運行狀態。當用戶點擊返回或則FINISH()了該Activity,那麼它便會被從棧中壓出,隨之摧毀,按照Activity的生命周期可以知道,如果當前顯示的棧中Activity沒有被摧毀,那麼打開新的Activity時候,會將新打開的壓入到棧,原來的根據其顯示情況選擇狀態變化(原Activity依舊可見,變為暫停狀態(Paused),如果被完成遮住了,轉變為停止狀態(Stopped))。

3.Task


Task是與Activity相關的一個重要概念,它密切聯係著Activity棧,它簡單的說,就是一組以棧的模式聚集在一起的Activity組件集合。(這裏隻提它和Activity的啟動模式來講)

4.Activity啟動模式


屬性:android:launchMode  
作用:用於指示Activity如何啟動。
描述:這裏有四種模式,與Intent對象中的Activity Flags的屬性(FLAG_ACTIVITY_*變量)共同作用,來決定Activity如何啟動來處理Intent。
四種模式
    "standard"  --默認模式
    "singleTop"
    "singleTask"
    "singleInstance"

以下舉例說明它們的區別:


standardActivity的默認加載方法,該方法會通過跳轉到一個新的activity,同時將該實例壓入到棧中(不管該activity是否已經存在在Task棧中,都是采用new操作)。例如: 棧中順序是A B C D ,此時D通過Intent跳轉到A,那麼棧中結構就變成 A B C D A ,點擊返回按鈕的 顯示順序是 D C B A,依次摧毀。


singleTopsingleTop模式下,當前Activity D位於棧頂的時候,如果通過Intent跳轉到它本身的Activity (即D),那麼不會重新創建一個新的D實例,所以棧中的結構依舊為A B C D,如果跳轉到B,那麼由於B不處於棧頂,所以會新建一個B實例並壓入到棧中,結構就變成了A B C D B。


singleTasksingleTask模式下,Task棧中隻能有一個對應Activity的實例。例如:現在棧的結構為:A B C D。此時D通過Intent跳轉到B,則棧的結構變成了:A B。其中的C和D被棧彈出銷毀了,也就是說位於B之上的實例都被銷毀了。


singleInstancesingleInstance模式下,會將打開的Activity壓入一個新建的任務棧中。例如:Task棧1中結構為:A B C ,C通過Intent跳轉到了D(D的模式為singleInstance),那麼則會新建一個Task 棧2,棧1中結構依舊為A B C,棧2中結構為D,此時屏幕中顯示D,之後D通過Intent跳轉到D,棧2中不會壓入新的D,所以2個棧中的情況沒發生改變。如果D跳轉到了C,那麼就會根據C對應的launchMode的在棧1中進行對應的操作,C如果為standard,那麼D跳轉到C,棧1的結構為A B C C ,此時點擊返回按鈕,還是在C,棧1的結構變為A B C,而不會回到D。


5.Activity棧和Task聯係


Task簡單的就是一組以棧的模式聚集在一起的Activity組件集合,類似於一個填充了Activity的容器,最先加入的Activity會處於容器最下麵,最後加入的處於容器最上麵而從Task中取出Activity是從最頂端先取出,最後取出的是最開始添加Activity,這就是後進先出(Last In First Out)模式,而Activity在Task中的順序是可以控製的,在Activity跳轉時用到Intent Flag可以設置新建activity的創建方式(這裏就涉及到了Intent Flag的使用)。

6.Intent Flags 


Flags: 表示Intent的標誌位,常用於Activity的場景中,它和Activity的啟動模式有著密切的聯係。

下麵列舉的是和本文主題相關的Flags屬性:

Intent.FLAG_ACTIVITY_NEW_TASK (默認)

默認的跳轉類型,它會重新創建一個新的Activity,不過與這種情況,比如說Task1中有A,B,C三個Activity,此時在C中啟動D的話,如果在AndroidManifest.xml文件中給D添加了Affinity的值和Task中的不一樣的話,則會在新標記的Affinity所存在的Task中壓入這個Activity。如果是默認的或者指定的Affinity和Task一樣的話,就和標準模式一樣了啟動一個新的Activity.

FLAG_ACTIVITY_SINGLE_TOP

這個FLAG就相當於啟動模式中的singletop,例如:原來棧中結構是A B C D,在D中啟動D,棧中的情況還是A,B,C,D。

FLAG_ACTIVITY_CLEAR_TOP

這個FLAG就相當於啟動模式中的SingleTask,這種FLAG啟動的Activity會把要啟動的Activity之上的Activity全部彈出棧空間。例如:原來棧中的結構是A B C D ,從D中跳轉到B,棧中的結構就變為了A B了。(這個方法可以用來關閉多個Activity,之後的一篇博文裏麵會提到)

FLAG_ACTIVITY_BROUGHT_TO_FRONT

這個網上很多人是這樣寫的。如果activity在task存在,拿到最頂端,不會啟動新的Activity。這個有可能會誤導大家! 他這個FLAG其實是這個意思!比如說我現在有A,在A中啟動B,此時在A中Intent中加上這個標記。此時B就是以FLAG_ACTIVITY_BROUGHT_TO_FRONT方式啟動,此時在B中再啟動C,D(正常啟動C,D),如果這個時候在D中再啟動B,這個時候最後的棧的情況是 A,C,D,B。如果在A,B,C,D正常啟動的話,不管B有沒有用FLAG_ACTIVITY_BROUGHT_TO_FRONT啟動,此時在D中啟動B的話,還是會變成A,C,D,B的。

FLAG_ACTIVITY_NO_USER_ACTION

onUserLeaveHint()作為activity周期的一部分,它在activity因為用戶要跳轉到別的activity而要退到background時使用。比如,在用戶按下Home鍵,它將被調用。比如有電話進來(不屬於用戶的選擇),它就不會被調用。
那麼係統如何區分讓當前activity退到background時使用是用戶的選擇?

它是根據促使當前activity退到background的那個新啟動的Activity的Intent裏是否有FLAG_ACTIVITY_NO_USER_ACTION來確定的。

注意:調用finish()使該activity銷毀時不會調用該函數

FLAG_ACTIVITY_NO_HISTORY

意思就是說用這個FLAG啟動的Activity,一旦退出,它不會存在於棧中,比方說!原來是A,B,C這個時候再C中以這個FLAG啟動D的,D再啟動E,這個時候棧中情況為A,B,C,E。

7.Activity相關屬性taskAffinity


Activity 中的 android:taskAffinity 這個屬性介紹:

   Activity為Task擁有的一個affinity。擁有相同的affinity的Activity理論上屬於相同的Task(在用戶的角度是相同的“應用程序”)。Task的affinity是由它的根Activity決定的。 
   affinity決定兩件事情——Activity重新宿主的Task(參考allowTaskReparenting特性)和使用FLAG_ACTIVITY_NEW_TASK標誌啟動的Activity宿主的Task。
    默認情況,一個應用程序中的所有Activity都擁有相同的affinity。捏可以設定這個特性來重組它們,甚至可以把不同應用程序中定義的Activity放置到相同的Task中。為了明確Activity不宿主特定的Task,設定該特性為空的字符串。
    如果這個特性沒有設置,Activity將從應用程序的設定那裏繼承下來(參考<application>元素的taskAffinity特性)。應用程序默認的affinity的名字是<manifest>元素中設定的package名。


注:以上的android:taskAffinity隻有通過標誌位為FLAG_ACTIVITY_NEW_TASK的Intent啟動Activity時,該Activity的這個屬性才會生效,係統才會將具有相同Task親和力的Task切換到前台,然後啟動該Activity,否則該Activity仍然運行在啟動它的Task中。


    上麵總結了下Activity啟動模式 及 Intent Flags 與 棧 的關聯分析,便於之後一篇文章中跳轉模式的了解使用。

最後更新:2017-04-03 16:49:23

  上一篇:go java.util.concurrent包(3)——線程間通信wait/notify和await/signal
  下一篇:go 實例:Netty 處理 TCP協議數據分包問題