Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 【Android基礎】Activity啟動模式以及Intent Flags 與 棧 的全面解析

【Android基礎】Activity啟動模式以及Intent Flags 與 棧 的全面解析

編輯:關於android開發

【Android基礎】Activity啟動模式以及Intent Flags 與 棧 的全面解析


Android開發的過程中,Intent是我們最常用Android用於進程內或進程間通信的機制。
Intent主要用於2種情景下:發起意圖 、廣播

其底層實現原理不在此篇文章的討論范圍,以後會陸續更新上的。
下面我就根據近期學習,總結記錄下Activity啟動模式 及 Intent Flags 與 棧 的關聯分析。


1、首先我們先搞清楚什麼是棧:

棧是一種常用的數據結構,棧只允許訪問棧頂的元素,棧就像一個杯子,每次都只能取杯子頂上的東西,而對於棧就只能每次訪問它的棧頂元素,從而可以達到保護棧頂元素以下的其他元素.”先進後出”或”後進先出”就是棧的一大特點,先進棧的元素總是要等到後進棧的元素出棧以後才能出棧.遞歸就是利用到了系統棧,暫時保存臨時結果,對臨時結果進行保護.

定義棧(Stack)
棧的定義棧(Stack)是限制僅在表的一端進行插入和刪除運算的線性表。
(1)通常稱插入、刪除的這一端為棧頂(Top),另一端稱為棧底(Bottom)。
(2)當表中沒有元素時稱為空棧。
(3)棧為後進先出(Last In First Out)的線性表,簡稱為LIFO表。棧的修改是按後進先出的原則進行。每次刪除(退棧)的總是當前棧中”最新”的元素,即最後插入(進棧)的元素,而最先插入的是被放在棧的底部,要到最後才能刪除。

棧的操作:壓棧、彈棧

2.Activity中的棧

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”

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

singleTop:singleTop模式下,當前Activity D位於棧頂的時候,如果通過Intent跳轉到它本身的Activity (即D),那麼不會重新創建一個新的D實例,所以棧中的結構依舊為A B C D,如果跳轉到B,那麼由於B不處於棧頂,所以會新建一個B實例並壓入到棧中,結構就變成了A B C D (你可以簡單理解這個模式的作用是保證棧頂不能有相同的實例)。

singleTask:singleTask模式下,Task棧中只能有一個對應Activity的實例。例如:現在棧的結構為:A B C D。此時D通過Intent跳轉到B,則棧的結構變成了:A B。其中的C和D被棧彈出銷毀了,也就是說位於B之上的實例都被銷毀了。也就是說:singleTask模式的Activity不管是位於棧頂還是棧底,再次運行這個Activity時,都會destory掉它上面的Activity來保證整個棧中只有一個自己,(注意此時不會銷毀該activity的實例這點與FLAG_ACTIVITY_CLEAR_TOP是不同的)切記切記”這點是毋庸置疑的。

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的啟動模式有著密切的聯系。

Affinity(吸引力)和新任務

默認情況下,一個應用程序中的activity相互之間會有一種Affinity──也就是說,它們首選都歸屬於一個任務。然而,可以在元素中把每個activity的taskAffinity屬性設置為一個獨立的affinity。於是在不同的應用程序中定義的activity可以享有同一個affinity,或者在同一個應用程序中定義的activity有著不同的affinity。affinity在兩種情況下生效:當加載activity的Intent對象包含了FLAG_ACTIVITY_NEW_TASK 標記,或者當activity的allowTaskReparenting屬性設置為“true”。

FLAG_ACTIVITY_NEW_TASK標記

如前所述,在默認情況下,一個新activity被另外一個調用了startActivity()方法的activity載入了任務之中。並壓入了調用者所在的堆棧。然而,如果傳遞給startActivity()的Intent對象包含了FLAG_ACTIVITY_NEW_TASK標記,系統會為新activity安排另外一個任務。一般情況下,如同標記所暗示的那樣,這會是一個新任務。然而,這並不是必然的。如果已經存在了一個與新activity有著同樣affinity的任務,則activity會載入那個任務之中。如果沒有,則啟用新任務。

allowTaskReparenting 屬性

如果一個activity將allowTaskReparenting屬性設置為“true”。它就可以從初始的任務中轉移到與其擁有同一個affinity並轉向前台的任務之中。比如說,一個旅行應用程序中包含的預報所選城市的天氣情況的activity。它與這個應用程序中其它的activity擁有同樣的affinity(默認的affinity)而且允許重定父級。你的另一個activity啟動了天氣預報,於是它就會與這個activity共處與同一任務之中。然而,當那個旅行應用程序再次回到前台的時候,這個天氣預報activity就會被再次安排到原先的任務之中並顯示出來。

如果在用戶的角度看來,一個.apk文件中包含了多於一個的“應用程序”,你可能會想要為它們所轄的activity安排不一樣的affinity。

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

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注意這裡說了是類似****SingleTask是不會銷毀本實例的,而FLAG_ACTIVITY_CLEAR_TOP則跟新啟動的activity的啟動模式有關,在默認情況下(standard)是該實例以上連同自己都會被銷毀然後重新創建的位於棧頂的,其他模式再根據其他的模式啟動。singleTask不會銷毀activity的實例,FLAG_ACTIVITY_CLEAR_TOP會把他上面的彈出,但是自身也銷毀,然後重新創建個新對象。singleTop和FLAG_ACTIVITY_CLEAR_TOP結合才能達到singleTask的效果。

FLAG_ACTIVITY_BROUGHT_TO_FRONT

如果設置了這個標志,而且被啟動的Activity如果已經在運行,那這個Activity會被調到棧頂。

比如,一個任務中有4個Activity:A,B,C,D。如果D調用了startActivity() 來啟動B時使用了這個標志,那B就會被調到歷史棧的棧頂,結果順序:A,C,D,B,否則順序會是:A,B,C,D,B。 如果使用了標志 FLAG_ACTIVITY_CLEAR_TOP,那這個FLAG_ACTIVITY_REORDER_TO_FRONT標志會被忽略。

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將從應用程序的設定那裡繼承下來(參考元素的taskAffinity特性)。應用程序默認的affinity的名字是元素中設定的package名。

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

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