1. 程式人生 > >Activity四種啟動模式的認識

Activity四種啟動模式的認識

最近看了一些前輩的文章,有了一些新的認識,不僅僅是知識,包括對待事情的態度。記錄下來,作為自己態度的見證。首先在android中對於Activity的例項是通過棧(Task)來進行管理的,棧是一種先進後出的資料結構。主要的操作就是進棧和出棧。簡單的如下圖所示。 在這裡插入圖片描述 Acticity的啟動模式一共四種分別是standard singleTop singleTask singleInstance,他們的配置是在AndroidManifestwenjian裡面通過android:launchMode設定的如

<activity
            android:name=".SecondActivity"
            android:launchMode="singleTop" />

下面對這四個模式分別講解。 首先我的測試專案是在一個MainActivity裡面放置了4個按鈕,每個按鈕對應一種不同的啟動模式。然後在每個Activity的onCreate方法中列印了(TAG)類名,方法名,任務棧的id,和當前類的hashCode值,這個值可以用來判斷是否新增加了該類的例項。列印語句 Log.e(TAG, “onCreate” + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());所有的測試都是從MainActivity開始的。 一。standard 這是Activity預設的啟動效果,當你沒有設定launchMode的時候就是這種效果,在這種模式下,只要啟動一個Activity就會增加一個新的例項並新增進棧裡面。這裡我進入的FirstActivity(啟動模式就是standard),當進入了FirstActivity之後我在FirstActivity中用一個按鈕跳轉連續啟動了4次FirstActivity(實際中肯定不會有這種操作 這裡是為了試驗效果)可以看看列印資訊 在這裡插入圖片描述

可以看到每次FirstActivity都執行了onCreate方法 並且每次hashCode值也是不一樣的,所以就正式了開始說的每次啟動都會建立新的例項併入棧。 二。singleTop 那就有問題了啊,我的例項既然已經在棧頂了,為什麼還要重新建立呢?於是乎就有了第二種啟動方式了,在這種模式下首先會檢測棧頂是否是需要啟動的Activity的例項,如果不是,就直接建立,如果是的話,就不在建立新的例項,而是呼叫Activity的onNewIntent方法來喚醒這個Activity(不會執行onCreate)。同樣的首先我先從MainActivity進入到SecondActivity(啟動模式是singleTop),同樣在SecondActivity中連續啟動幾次SecondActivity。我們來看看列印資訊 在這裡插入圖片描述
可以看到第一次進SecondActivity的時候執行的onCreate,之後啟動的時候都是執行的onNewIntent方法,且每個SecondActivity的hashCode值是一樣的,這就說明此時只有一個SecondActivity的例項。剛才已經說過了,由於SecondActivity已經在棧頂了,所以是不會再去建立例項的。 那麼接下來我們來看看當棧的頂部不是SecondActivity的時候又會有什麼情況出現呢?這次我先進入SecondActivity然後從SecondActivity跳到FirstActivity(standard模式)再跳到SecondActivity。也就是說SecondActivity不在棧頂了。同樣看列印資訊 在這裡插入圖片描述 很顯然這次兩個SecondActivity的hashCode值不一樣了,也就證明建立了新的例項。 三。singleTask 這個模式相對於前面兩個模式就顯得更復雜了,不知道你有沒有發現前面講的兩種啟動模式的TaskId是一樣的,也就是說前面的兩種模式只是影響了Activity的例項,並沒有影響棧的情況。因此這個模式我決定分成兩個部分。首先第一種情況是不影響棧的時候。這種情況下會先檢測棧中是否有例項,沒有就建立,如果有就把該例項之上的其他例項全部移出棧。同樣的這次先從MainActivity進入ThirdActivity(singleTask)再進入FirstActivity(standard)再跳到ThirdActivity,我們一起來看看列印資訊。 在這裡插入圖片描述 可以簡單分析一下,第一次進入ThirdActivity直接新建一個例項,接著進入FirstActivity此時FirstActivity也建立了例項(畢竟都是第一次進來,肯定要建立的)這時候從FirstActivity跳轉到ThirdActivity,由於棧裡面已經有ThirdActivity的例項了,所以不會再建立而是呼叫了onNewIntent方法。 第二種,會影響棧的時候。在Activity裡面還可以配置一個taskAffinity屬性。

<activity
            android:name=".ThirdActivity"
            android:launchMode="singleTask"
            android:taskAffinity="com.win.star" />

這個屬性你可以把它理解成棧的名字,預設是工程下的包名(這個看到別的文章這麼寫的但是不知道怎麼驗證)。這次我們先從MainActivity進入到ThirdActivity(這次配置了taskAffinity)看看列印內容 在這裡插入圖片描述 可以看到兩個TaskId是不一樣的,這就說明他們進入了不同的棧。由於我們現在停留在ThirdActivity上,那麼如果我們這是在ThirdActivity再上啟動一個Activity的話,新的Activity(是standard模式)例項在哪個棧裡面呢?看看結果 在這裡插入圖片描述 這個時候新啟動的Activity例項位於ThirdActivity指定的新棧中,如果在ThirdActivity上再次啟動指定了taskAffinity屬性的Activity是否還會再建立一個新的棧呢?答案是會的。來看看結果 在這裡插入圖片描述 這裡我把FirstActivity 和ThirdActivity都指定為singleTask且配置了不一樣的taskAffinity。從MainActivity到ThirdActivity再到FirstActivity可以看到每個Activity的TaskId是不一樣的然後再ThirdActivity與FirstActivity之間互相跳轉始終都不會涉及到MainActivity那個棧。同理我也測試了第一個指定taskAffinity第二個不指定taskAffinity屬性的還是直接看結果 在這裡插入圖片描述 這裡的順序是MainActivity–>ThirdActivity–>FirstActivity 其中ThirdActivity和FirstActivity啟動模式都是singleTask,但是ThirdActivity我指定了taskAffinity而FirstActivity沒有指定,結果發現FirstActivity的例項和MainActivity的例項在一個棧裡面。(如果不理解就多想想指定和不指定有什麼影響吧) 四。singleInstance *( 該模式具備singleTask模式的所有特性外,與它的區別就是,這種模式下的Activity會單獨佔用一個Task棧,具有全域性唯一性,即整個系統中就這麼一個例項,由於棧內複用的特性,後續的請求均不會建立新的Activity例項,除非這個特殊的任務棧被銷燬了。以singleInstance模式啟動的Activity在整個系統中是單例的,如果在啟動這樣的Activiyt時,已經存在了一個例項,那麼會把它所在的任務排程到前臺,重用這個例項。)*我是這麼理解這個模式,在該模式下建立Activity例項的時候會新開一個棧。且該棧中也只有這一個例項。首先還是從MainActivity進入到FourthActivity(模式是singleInstance)然後再進入到FirstActivity(模式是standard)先看結果 在這裡插入圖片描述 可以看到MainActivity和FirstActivity在一個棧裡面,而FourThActivity在另外一個單獨的棧裡面。除了看列印的資訊以為,你還可以在控制檯輸入命令adb shell dumpsys activity activities可進行檢視結果如下 在這裡插入圖片描述 如果在singleInstance模式下再次啟動一個模式為singleInstance的Activity還會繼續新開一個棧的。這次測試順序是這樣的MainActivity–>FourthActivity(singleInstance) -->FiveActivity(singleInstance) --> FirstActivity(standard) 結果是這樣的 在這裡插入圖片描述 最終FirstActivity和MainActivity在一個棧裡面。其餘兩個都在不同的棧裡面。由於這種組合實在太多了,有興趣的可以自己多試試,原始碼太簡單就是頁面跳轉。 最後做一下小總結。 1.standard:每次啟動都會新建一個例項。 2.singleTop:啟動時看是否有例項,沒有就建立。如果有看是否在棧頂,如果在棧頂就直接複用不再新建否則會新建。 3.singleTask:首先看是否配置了taskAffinity,如果配置了就新開一個棧。如果沒有配置就來看棧中是否有例項,如果有就將例項之上的其他例項移出棧,如果沒有就新建。 4.singleInstance:新開一個棧,這個棧只有這一個例項物件。 最後本文是基於一些前輩的文章,結合自己的實際體驗得到的結果。總的來說很多東西自己看看覺得沒什麼大不了的,但是當你自己去動手去實踐真的會有所收穫的。 參考文章:

最後的最後,鑑於筆者水平有限,若有錯誤,還望不吝賜教!