Android Activity啓動模式

Android Activity啓動模式

Activity作爲Android四大組件之首,它非常重要,有時候爲了項目的需要,就必須使用Activity的啓動模式,所以我們必須要搞清楚Activity的啓動模式和標誌位:


1 .Activity的LaunchMode

我們知道,在默認情況下,我們多次啓動同一個Activity的時候,系統會創建多個實例並把它們一一放入任務棧中,當我們單擊這個back建,會發現這些Activity會一一回退,任務棧是一種“後進先出”的棧結構,這個好理解,每按一下back鍵就會有一個Activity出棧,直到棧空爲止,當棧中無任何Activity的時候,系統就會回收這個任務棧。我們就會發現,多次啓動同一個Activity,系統會重複創建多個Activity實例,這樣會造成一些不必要的內存開銷,所以Android在設計的時候,提供了啓動模式來修改系統的默認行爲,目前有四種啓動模式:standard,singleTop,singleTask和SingleInstance

(1). standard:標準模式

也就是系統的默認模式,每次啓動一個Activity就會創建一個新的新的實例,不管這個實例是否存在。被創建的實例的聲明週期符合典型情況下Activity的生命週期,它的onCreate、onStart、onResume都會被調用,這是一種典型的多實例實現,一個任務棧中可以有多個實例,每個實例也可以屬於不同的任務棧。在這種模式下,誰啓動了這個Activity,那麼這個Activity就運行在啓動它的那個Activity所在的棧中。比如Activity A啓動了Activity B(B是標準模式),那麼B就會進入A所在的棧中。不知道大家有沒有遇到當我們用ApplicationContext去啓動Activity的時候會保存,錯誤如下:
這裏寫圖片描述
相信我們並不陌生這句話,這是因爲standard模式的Activity會默認進入啓動它的Activity所屬的任務棧中,但是由於非Activity類型的Context(如ApplicationContext)並沒有所屬的任務棧,所以這就有問題了,解決這個問題的方法是爲待啓動的Activity指定FLAG_ACTIVITY_NEW_TASK標記位。這樣啓動的時候就會爲它創建一個新的任務棧,這個時候待啓動的Activity實際上是以singleTask模式啓動的,大家可以仔細體會。

(2). singleTop:棧頂複用模式

在這種模式下,如果新的Activity已經位於任務棧的棧頂,那麼此Activity不會被重新創建,同時它的onNewIntent方法會被回調,通過此方法的參數我們可以取出當前請求的信息。需要注意的是,這個activity的onCreate、onStart不會被系統調用,因爲它並沒有發生改變。如果新的Activity實例已經存在但不是位於棧頂,那麼新的Activity仍然會被重新創建,舉個例子,假設目前棧內的情況爲ABCD,其中ABCD爲四個Activity,A位於棧底,D位於棧頂,這個時候假設要再次啓動D,如果D的啓動模式爲singleTop,那麼棧內的情況仍然爲ABCD;如果D的啓動模式爲standard,那麼由於D被重新創建,導致棧內的情況就變爲CBCDD.

(3). SingleTask:棧內複用模式

棧內複用模式。這是一種單例實例模式,在這種模式下,只要Activity在棧中存在,那麼多次啓動此Activity都不會重新創建實例,和singleTop一樣,系統也會回調其onNewIntent。具體一點,當一個具有singleTask模式的Activity請求啓動後,比如Activity A,系統會首先尋找是否存在A想要的任務棧,如果不存在,就重新創建一個任務棧,然後創建A的實例後把A放到棧中。如果存在A所需的任務棧,這時要看A是否在棧中存在,如果有實例存在,那麼系統就會把A調到棧頂並調用的它的onNewIntent方法,如果實例不存在,就創建A的實例並把A壓入棧中。舉幾個例子:

  • 比如目前任務棧S1中的情況爲ABC,這個時候Activity D以singleTask 模式請求啓動,其所需要的任務棧爲S2,由於S2和D的實例均不存在,所以系統會先創建任務棧S2,然後創建D的實例並將其壓入到S2。
  • 另外一種情況,假設D所需的任務棧爲S1,其它情況 如上面例子1所示,那麼由於S1已經存在,所以系統會直接創建D的實例並將其壓入棧到S1。
  • 如果D所需的任務棧爲S1,並且當前的任務棧S1的情況爲ADBC,根據棧內複用的遠側,此時D不會重新創建,系統會把D切換到棧頂並調用其onNewIntent方法,同時由於singleTask默認具有clearTop的效果,會導致棧內所有在D上面的Activity全部出棧,於是S1中的情況爲AD。這一點比較特殊。

(4). singleInstance:單例實例模式

單例實例模式,這是一種加強的singleTask模式,它除了具有singleTask模式所有的特性外,還加強了一點,那就是具有此模式的activity只能單獨的位於一個任務棧中,比如Activity A是singleInstance模式,當A啓動後,系統會爲它創建一個新的任務棧,然後A獨自存在這個新的任務棧中,由於棧內複用的特性,後續的請求均不會創建新的Activity,除非 這個獨特的任務棧被系統銷燬了。


2. 總結

上面介紹了幾種啓動模式後,這裏需要指出一種情況,我們假設目前有兩個任務棧,前臺任務棧的情況爲AB,而後臺任務棧的情況爲CD,假設CD的啓動模式均爲singleTask,現在請求啓動D,那麼整個後臺任務棧都會被切換到前臺,這個時候整個後退列表變成了ABCD,當用戶按back鍵的時候,列表中的Activity會一一出棧,如圖任務棧示例1所示;
這裏寫圖片描述
如果不是啓動D,而是請求啓動C,那麼情況就會不一樣了,請看圖任務棧示例2:

這裏寫圖片描述

另外一個問題是:在singleTask啓動模式中,多次提到某個Activity所需的任務棧,什麼是Activity所需的任務棧?,這要從一個參數說起:TaskAffinity,可以翻譯爲任務相關性。這個參數表示了一個Activity所需的任務棧的名字,默認情況下,所有Activity所需的任務棧的名字爲應用的包名。當然,我們可以爲每個Activity都單獨制定TaskAffinity屬性,這個屬性必須和包名不能相同,否則就相當於沒有指定。TaskAffinity屬性主要和singleTask啓動模式或者allowTaskReparenting屬性配對使用,在其它情況下沒有意義。另外,任務棧分爲前臺任務棧和後臺任務棧,後臺任務棧中的Activity位於暫停狀態,用戶可以通過切換後臺任務棧再次調到前臺。

  • 當TaskAffinity和singleTask啓動模式配對使用的時候,它是具有該模式的activity的目前任務棧的名字,待啓動的activity會運行在名字和TaskAffinity相同的任務棧中。
  • 當TaskAffinity和allowTaskReparenting結合的時候,情況比較複雜,會產生特殊的效果,當一個應用A啓動了一個應用B的某個ActivityB後,如果這個Activity的allowTaskReparenting屬性爲true的話,那麼當應用B被啓動後,此Activity會直接從應用A的任務棧轉移到B的任務棧中。還是很抽象,舉個例子,比如現在有兩個2應用A和B,A啓動了B的一個Activity C,然後按Home鍵返回到桌面,然後再單擊B的桌面圖標。這個時候並不是啓動了B的主Activity,而是重新顯示了已經被應用啓動的Activity C,或者說C從A的任務棧轉移到了B的任務棧中,可以這麼理解,由於A啓動了C,這個時候C只能運行在A的任務棧中,但是由於C屬於B應用,正常情況下,它的TaskAffinity的值肯定不能和A的任務棧相同(因爲包名不同),所以當B被啓動後,B會創建自己的任務棧,這個時候,系統發現C原本所想要的任務棧已經被創建了,所以就把C從A的任務棧中轉移過來了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章