好久以前就知道android
的Activity
有不同的啟動方式,但開始始終沒有弄明白,現(xiàn)在終于梳理清了。
任務(wù)棧
Activity
一共有四種不同的啟動模式,分別是standard
、singleTop
、singleTask
、singleInstance
,不同的啟動模式,就讓activity存在于內(nèi)存中不同的任務(wù)棧和棧里的位置。這里我們提到了一個任務(wù)棧,其實就是一個后進(jìn)先出
的容器,里面存放著Activity
。
在這樣一個任務(wù)棧里面,相當(dāng)于先讓Activity_A
進(jìn)棧(直接啟動Activity_A
),然后再讓Activity_B
進(jìn)棧(從Activity_A
以某種模式啟動Activity_B
,具體什么方式后面就講),剩下的Activity_C
、Activity_D
也是按照這種方式進(jìn)棧。然后就是出棧了,首先我們明白現(xiàn)在的任務(wù)棧中有4個Activity
,接著當(dāng)我們按手機的back
鍵的時候,就會按照D,C,B,A出棧,這也就是所說的先進(jìn)后出
。當(dāng)然,屏幕顯示的就是棧頂?shù)脑亓恕?/p>
四種啟動模式
一.standard (標(biāo)準(zhǔn)模式)
standard
字面意思就是標(biāo)準(zhǔn),沒錯,就是標(biāo)準(zhǔn)模式。當(dāng)Activity
以標(biāo)準(zhǔn)模式啟動的時候,就會把該Activity
給放入棧頂。沒錯,我們上面的例子就可以用standard
模式啟動。
二.singleTop(棧頂復(fù)用模式)
singleTop
模式就是講,當(dāng)我們以singleTop
啟動Activity的時候,如果這時候的棧頂元素也是我們的需要啟動的Activity
,那么這個Activity
就不會再次被創(chuàng)建,而是回調(diào)onNewIntent
方法。
其實這個還是很好理解的,也就和字面意思一樣。好,我們看上面的任務(wù)棧,左邊就是我們開始的樣子(DCBA),然后我們再以singleTop
模式去啟動D,然后,發(fā)現(xiàn)任務(wù)棧中還是(DCBA)。這就是棧頂復(fù)用模式。
二.singleTask(棧內(nèi)復(fù)用模式)
singleTask
是我覺得這幾種模式中最難理解的,但是慢慢理一下,發(fā)現(xiàn)還是挺簡單的。
以singleTask
模式啟動的Activity
首先就會尋找自己需要的任務(wù)棧,如果沒有,就會創(chuàng)建一個,然后把自己給放進(jìn)棧里面。要是有發(fā)現(xiàn)自己需要的任務(wù)棧,就會看里面有沒有這個Activity
的實例,沒有的話就在棧頂加入新創(chuàng)的實例,要是有的話就會彈出該實例上面的所有元素,從而把所需求的實例給推到棧頂。
這樣一說,肯定都還是模模糊糊的,不用怕,我們慢慢理。首先,這里我們提出了一個新的術(shù)語,"Activity
需要的任務(wù)棧"。這里我們需要明白,當(dāng)我們沒有為Activity
給指定任務(wù)棧的話,那它默認(rèn)的就是我們項目的包名。當(dāng)然,我們可以為其指定一個任務(wù)棧。
<activity
android:name=".Activity_C"
android:label="@string/title_activity_activity__c"
android:taskAffinity="com.mathias.www"
android:theme="@style/AppTheme.NoActionBar" />
在Activity
標(biāo)簽中,通過taskAffinity
(任務(wù)相關(guān)性)給指定的字符串(字符串中必須包含分割符” . “),這樣當(dāng)我們以singleTask
啟動該Activity
的時候,就會新建一個任務(wù)棧。但是一般來說我們的Activity
都是以默認(rèn)的taskAffinity
啟動的。
相同的任務(wù)棧
就如上圖一樣,起初我們的任務(wù)棧中有DCBA
四個元素,接著,我們以singleTask
模式啟動B
,那么B
就不會被重新創(chuàng)建,而是回調(diào)onNewIntent
方法,并且,它還會清掉它上面的元素DC
(clearTop效果),這時候你按back
鍵的話就是返回到A
。
不同的任務(wù)棧
圖中,我們起初的默認(rèn)任務(wù)棧中有BA
兩個元素,然后我們以singleTask
(不同的任務(wù)棧,即改變了taskAffinity
)啟動C
,那么C
就會被放到另一個任務(wù)棧中,同時,由于C
在前臺,所以C
屬于的任務(wù)棧也會被變成我們的前臺任務(wù)棧。
當(dāng)然,有些人可能會說,C
不在默認(rèn)的任務(wù)棧中了,但是我們按back
鍵還是會回到B
呀?對,當(dāng)然會回到B
。當(dāng)前臺任務(wù)棧返回的是時候棧里已經(jīng)沒有了元素了,所以就會返回到后臺任務(wù)棧了。
或許你又會說,那這樣啟動Activity
有什么作用嗎?好吧,當(dāng)我們在同一個應(yīng)用以不同的任務(wù)棧啟動的時候,好像這個作用并不大(怪我自己還沒找到),但是在一個應(yīng)用代開另一個應(yīng)用的時候就起作用了,當(dāng)一個應(yīng)用A打開了另一個應(yīng)用B的Acctvity
后,再返回Home
,打開應(yīng)用B,就發(fā)現(xiàn)B沒有在主界面,而是開始A打開的界面,當(dāng)然這里還需要一個Activity
的屬性支持 android:allowTaskReparenting="true"
。
singleInstance(單實例模式)
所謂的singleInstance
模式,首先,它具備上一個singleTask
的所有屬性,其次,它只能獨自的存在于一個單獨的任務(wù)棧。簡單點就是說,當(dāng)以singleInstance
啟動Activity
的時候,會為它創(chuàng)建一個新的任務(wù)棧,而且這個任務(wù)棧只會有它一個Activity
,后續(xù)的請求也都不會再重新創(chuàng)建它了,所以叫做單例
。
好吧,我們還是簡單的分析一下(搞什么,圖和上面的一樣):假設(shè)我們當(dāng)前任務(wù)棧中有BA
,接著我們以singleInstance
模式啟動C
,那么C
就會在一個獨立的任務(wù)棧中了,然后我們的請求可能會讓前臺任務(wù)棧又變成了默認(rèn)的(BA
),這時候,我們再啟動C
,就不會創(chuàng)建C
,而是直接把C
這個任務(wù)棧變成前臺任務(wù)棧,顯示C
。
也許你看過上面的分析又會有疑問了:明明上面的操作用singleTask
就能完成,為什么還要用singleInstance
?
的確,上面的操作換成singleTask
也是可以完成的,但是看我們這圖里面的情況,BA
為默認(rèn)的任務(wù)棧,C
為新建的。這時候,我們啟動一個和C
任務(wù)棧相同的D
,那么這里就會變成DC
。
然后,我們一系列的操作 ,又讓前臺任務(wù)棧變成了
BA
,我們這時候啟動C
,那么由于開始說的clearTop
屬性就會把D
給清理出去了。再創(chuàng)建D
的時候就會重建了,然而,如果使用的是singleInsatnce
的話就不會出現(xiàn)這種情況了,因為singleInstance
中只能有一個Activity
。
設(shè)置啟動模式
說了這么多,才發(fā)現(xiàn)還沒有講如何設(shè)置......
好吧,設(shè)置Activity
啟動模式有兩種方法,一種就是在AndroidManifest.xml
中Activity
的launchMode
:
<activity
android:name=".Activity_B"
android:launchMode="singleInstance"
android:allowTaskReparenting="true"
android:label="@string/title_activity_activity__b"
android:theme="@style/AppTheme.NoActionBar" />
另一種就是在代碼中設(shè)置標(biāo)志符了:
Intent intent = new Intent(Activity_A.this,Activity_B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
這兩種方式都可以設(shè)置,但是代碼設(shè)置的優(yōu)先級肯定是比在xml中高的(在代碼中先解析xml,再設(shè)置的)。
最后
還有,這些是我參考《Android開發(fā)藝術(shù)探索》的,對,就是任大大的。