天天看點

Activity啟動模式解析

Activity有四種啟動模式:standard,singleTop,singleTask,singleInstance。

關于這四種啟動模式的概念很容易找到,這裡我們先不介紹概念,而是通過實際操作,總結出不同模式的實際效果。

Task簡介

當然,要了解啟動模式,我們就不得不提到Task,直譯過來是“任務”,而實際上它的本質是一個棧,一個專門存儲activity的棧。通常情況下,當我們啟動一個新activity時,執行的是入棧操作,會把activity壓入棧。當點選傳回時,執行的是出棧操作,讓目前activity出棧,這樣就顯示出了上一個activity。

Activity啟動模式解析

啟動模式設定方式

此外,要了解啟動模式,還需要知道如何設定,啟動模式的設定有兩種方式,一種是在AndroidManifest.xml中進行配置,另一種是在啟動activity時設定intent的flag。

首先看AndroidManifest.xml中的設定:

Activity啟動模式解析

很簡單,就是這四種模式,當我們不設定的時候,預設是standard模式。

另一種方式則相對複雜,我們可以通過Intent的setFlags()或addFlags()方法來設定Flag,而Intent關于啟動模式的Flag有許多:

Activity啟動模式解析

我們可以同時設定一種或多種。幸運的是每個都有詳細的注釋和例子,當我們了解了啟動模式的原理以及熟悉了其中部分的應用方式,其他的也可以根據注釋很容易的進行應用。

通過Intent設定flag的方式的優先級要高于在AndroidManifest.xml中的配置。

Standard

首先我們來看一下最常用的standard模式:

Activity啟動模式解析

我寫了兩個簡單的應用,LaunchMode1一共有四個activity,他們可以互相跳轉。LaunchMode2有一個activity,可以和LaunchMode1互相跳轉。通過adb shell dumpsys activityactivities指令我們可以看到task棧的情況

執行:0——1——2——3:

Activity啟動模式解析

執行:0——0——0:

Activity啟動模式解析

執行:0——LaunchMode2——0:

Activity啟動模式解析

可以看到,無論是啟動同應用的activity,啟動自身,還是跨應用的activity,隻要是新啟動activity,都會在目前task内重新建立一個執行個體。這就是standard啟動模式。

SingleTop

接下來我們看一下singleTop模式:

這裡Intent的flag中有一個FLAG_ACTIVITY_SINGLE_TOP,和在AndroidManifest.xml中設定android:launchMode="singleTop"是一樣的。我們這裡采用的是AndroidManifest.xml設定方式。

執行:0——1——2——3:

Activity啟動模式解析

和standard模式一模一樣的結果,差點讓我以為是我設定錯了,我們看看下面會不會有差別。

執行:0——0——0:

Activity啟動模式解析

這裡就已經不一樣了。

執行:0——LaunchMode2——0:

Activity啟動模式解析

這個好像還是沒什麼差別。我們再試一組

執行:0——1——2——2:

Activity啟動模式解析

這裡也和standard不同,點了四次卻隻有三個記錄。結合singleTop的名字我們就可以看出來了。如果打開的avtivity剛好在棧的頂部,那麼就不會建立新的執行個體,而是打開原來的(那麼怎麼證明我點過了,而不是沒有任何操作呢?其實這時會執行onNewIntent()方法,可以在這裡執行我們想要的操作)。如果要打開的activity不再棧頂,則和standard模式一樣。

SingleTask

接下來是singleTask模式:

這個模式也有兩種設定方式:android:launchMode="singleTask"以及FLAG_ACTIVITY_NEW_TASK      
我們還是選擇在AndroidManifest.xm中設定。      

說到這種模式,我們不得不提到activity的一個屬性taskAffinity,從字面意思看,就是對任務棧的親和力。而事實上也差不多,它決定了activity運作在哪個task,預設是app的包名。

現在我們就把每個activity啟動模式設定為singleTask,并把activity3的taskAffinity屬性設定為“com.example.mjn.launchmodetest”

執行:0——1——2——3:

Activity啟動模式解析

可以看到012在一個task中,而3啟動了新的task,名字剛好是我們之前設定過的。

執行:0——1——2——1:

Activity啟動模式解析

這裡2被清除了

執行:0——1——LaunchMode2——0:

Activity啟動模式解析

這裡1被清除了

執行:0——3——LaunchMode2:

Activity啟動模式解析

不同應用由于預設包名不同,啟動在不同的task。

通過這幾個現象我們可以看到,首先activity會啟動到taskAffinity屬性設定的task中,預設是包名。而當activity在所需task中已經存在時,則會把之前的執行個體放到棧頂,把在該activity上面的執行個體全部推出棧。

SingleInstace

最後一個singleInstance模式

顧名思義,也就是單例模式,我們依然先看效果。

這裡有一點要注意的是singleInstance模式隻能通過manifest設定,不能在intent中設定,這個當我們明白他的原理後也很好了解。

執行:0——1——2——3:

Activity啟動模式解析

可以看到每個activity都在不同的task,而且taskAffinity屬性依然有效。

執行:0——1——2——1:

Activity啟動模式解析

每個acitivity都在自己獨立的task,互不影響。由此就可以看出singleInstance模式就是嚴格的單例模式,每個acitivty在一個task中且隻有一個執行個體,每個task隻有一個activity。這裡我們就能了解為什麼不能再intent中設定該模式了,因為singleInstance要求每個activity都在單獨的task,若不是一開始就設定為該模式,很可能出現task有多個activity,activity有多個執行個體等情況,造成問題。

總結

以上,就是四種啟動模式的介紹,我們來總結一下:

Standard:

       預設模式,啟動每個acitivity時都會在目前task建立新的執行個體。

SingleTop:

       當要啟動的activity在目标task頂部時,不會建立新執行個體,而是重用該執行個體并調用onNewIntent()方法。否則建立新執行個體。

SingleTask:

    當要啟動的activity不存在時,會在在目标task(目标task可又taskAffinity屬性設定)中建立新執行個體,若目标task中已存在該activity,則會重用該執行個體,并調用onNewIntent()方法,并把task棧中在它上面的activity移除。該模式下的Activity隻會有一個執行個體。

SingleInstance:

    當要啟動的acitivity不存在時,會在新task中建立一個執行個體,如果存在,則重用之前的執行個體。每個acitivity都在一個獨立的task中,隻有一個執行個體,每個task隻有一個執行個體。

對傳回鍵的影響

此外,我們在開始時就說過task還和傳回有關,我們點選傳回是顯示的activity就是由task決定的。我們上面每個關于棧内容的截圖都顯示了傳回的順序:

例如singleTask時執行:0——1——2——1:

Activity啟動模式解析
Activity啟動模式解析

就表示傳回時是1——0的順序。而和我們打開的順序并不相同,是以不同的啟動模式會對我們傳回操作産生影響。