通過昨天的學(xué)習(xí),相信大家已經(jīng)對(duì)Android Activity的四種啟動(dòng)模式有了非常清楚的認(rèn)識(shí),那么,Android Activity 這四種啟動(dòng)模式有什么區(qū)別呢?這就是今天本文要給大家講解的內(nèi)容!
1、standard標(biāo)準(zhǔn)模式
在standard模式也就是默認(rèn)模式下,不需要配置launchMode。此時(shí)的AndroidManifest.xml如代碼清單1-1所示。
代碼清單1-1 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="feixun.com.jiang"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Fx_Main"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Activity2" android:label="@string/Ac2"/>
<activity android:name=".Activity3" android:label="@string/Ac3/>
</application>
<uses-sdk android:minSdkVersion="4" />
</manifest>
運(yùn)行例子,從Fx_Main開始,一直點(diǎn)回到Activity2按鈕時(shí),Log信息如圖1所示。

圖1 Standard啟動(dòng)模式下Log信息
發(fā)現(xiàn)每次都創(chuàng)建了Activity2的新實(shí)例。standard的加載模式就是這樣的,Intent將發(fā)送給它新的Activity實(shí)例。
現(xiàn)在點(diǎn)擊Android設(shè)備的回退鍵,可以看到Log信息按照剛才創(chuàng)建Activity實(shí)例的倒序依次出現(xiàn),類似退棧的操作,而剛才操作跳轉(zhuǎn)按鈕的過程是壓棧的操作。
2、 singleTop
singleTop和standard模式,都會(huì)將Intent發(fā)送到新的實(shí)例(如果已經(jīng)有了,singleTask模式和singleInstance模式不發(fā)送到新的實(shí)例)。不過,singleTop要求如果創(chuàng)建intent時(shí)棧頂已經(jīng)有要?jiǎng)?chuàng)建Activity的實(shí)例,則將Intent發(fā)送給該實(shí)例,而不發(fā)送給新的實(shí)例。
還是用剛才的示例,只需將Activity2的launchMode改為singleTop,就能看到區(qū)別。修改后AndroidManifest.xml中代碼如代碼清單1-2所示。
代碼清單1-2 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="feixun.com.jiang"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Fx_Main"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Activity2" android:label="@string/Ac2"
android:launchMode="singleTop"/ >
<activity android:name=".Activity3" android:label="@string/Ac3/>
</application>
<uses-sdk android:minSdkVersion="4" />
</manifest>
運(yùn)行Fx_Main,跳轉(zhuǎn)到Activity2---->Actvity2時(shí)會(huì)發(fā)現(xiàn),單擊多少遍按鈕,都是相同的Activity2實(shí)例,因?yàn)樵搶?shí)例在棧頂,所以不會(huì)創(chuàng)建新的實(shí)例。如果回退,回到Fx_Main,將退出應(yīng)用,如圖2所示。

圖2 singleTop模式下“跳轉(zhuǎn)到AC2”的Log信息
singleTop模式,可用來解決棧頂多個(gè)重復(fù)相同的Activity的問題。
如果是Fx_Main跳轉(zhuǎn)到Activity2,再跳轉(zhuǎn)到Fx_Main,行為就和standard一樣了,會(huì)在Activity2跳轉(zhuǎn)到Fx_Main時(shí)創(chuàng)建Fx_Main的新實(shí)例,因?yàn)楫?dāng)時(shí)的棧頂不是Activity2實(shí)例,如圖3所示。

圖3 singleTop模式下“跳轉(zhuǎn)到AC2”后“跳回到Main”的Log信息
3、singleTask
singleTask模式和后面的singleInstance模式都是只創(chuàng)建一個(gè)實(shí)例的。
當(dāng)Intent到來,需要?jiǎng)?chuàng)建singleTask模式Activity時(shí),系統(tǒng)會(huì)檢查棧里面是否已經(jīng)有該Activity的實(shí)例。如果有直接將Intent發(fā)送給它(注意此時(shí)原在此Activity棧中上面的Activity將會(huì)被關(guān)閉)。
把Activity2的啟動(dòng)模式改成singleTask,修改后AndroidManifest.xml中代碼如代碼清單1-3所示。
代碼清單1-3 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="feixun.com.jiang"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Fx_Main"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Activity2" android:label="@string/Ac2"
android:launchMode="singleTask"/ >
<activity android:name=".Activity3" android:label="@string/Ac3/>
</application>
<uses-sdk android:minSdkVersion="4" />
</manifest>
啟動(dòng)Fx_Main,跳轉(zhuǎn)到Activity2---->Activity3---->Actvity2,此時(shí)看Log信息,如圖4所示。

圖4 singleTask啟動(dòng)模式下Log信息
可見從AC3再跳轉(zhuǎn)到AC2時(shí),因?yàn)锳C2之前在棧中是存在的所以不生成新的AC2實(shí)例,而是在棧中找到此AC2,并將在AC2上面的AC3關(guān)閉,所以此時(shí)棧中只有Fx_Main和AC2,在AC2點(diǎn)返回會(huì)直接退到Fx_Main然后退出。
4、singleInstance
在singleInstance模式下,加載該Activity時(shí)如果沒有實(shí)例化,它會(huì)在創(chuàng)建新的Task后,實(shí)例化入棧,如果已經(jīng)存在,則直接調(diào)用onNewIntent,該Activity的Task中不允許啟動(dòng)其他的Activity,任何從該Activity啟動(dòng)的其他Activity都將被放到其他Task中,先檢查是否有在應(yīng)用的Task,沒有的話就創(chuàng)建。
在這里介紹一下Task(任務(wù))的概念。按照字面意思,任務(wù)就是自己要實(shí)現(xiàn)的一個(gè)目的,而在Android中的Task的定義是一系列Activity的集合,即要達(dá)到自己終要到的Actvity,之前所有經(jīng)歷過的Actvity的集合。它可以是同一個(gè)應(yīng)用內(nèi)部的,也可以是兩個(gè)不同應(yīng)用的。Task可以認(rèn)為是一個(gè)棧,可放入多個(gè)Activity。比如,啟動(dòng)一個(gè)應(yīng)用,那么 Android就創(chuàng)建了一個(gè)Task,然后啟動(dòng)這個(gè)應(yīng)用的入口Activity,就是intent-filter中配置為main和launch的那個(gè)。這個(gè)Activity是根(Root)Activity,可能會(huì)在它的界面調(diào)用其他Activity,這些Activity如果按照上面那3個(gè)模式,也會(huì)在這個(gè)棧(Task)中,只是實(shí)例化的策略不同而已。
把Activity2的啟動(dòng)模式改成singleInstance,修改后AndroidManifest.xml中代碼如代碼清單1-4所示。
代碼清單1-4 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="feixun.com.jiang"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Fx_Main"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Activity2" android:label="@string/Ac2"
android:launchMode="singleInstance"/ >
<activity android:name=".Activity3" android:label="@string/Ac3/>
</application>
<uses-sdk android:minSdkVersion="4" />
</manifest>
然后進(jìn)行測(cè)試,啟動(dòng)Fx_Main---->Actvity2---->Actvity3然后看一下Log信息,如圖5所示。

圖5 singleInstance啟動(dòng)模式下Log信息
可以看到Fx_Main以及Activity3的Task ID為9,而Actvity2的Task ID為10,此時(shí)在Actvity3單擊“返回”按鈕會(huì)發(fā)現(xiàn)先退到Fx_Main,繼續(xù)返回會(huì)回到Actvity2后退出。從該過程可以看出:如果從其他應(yīng)用程序調(diào)用singleInstance模式的Activity(Fx_Main),從該Activity開啟其他Activity(Activity2)時(shí),會(huì)創(chuàng)建一個(gè)新的Task(Task ID為10的那個(gè)),實(shí)際上,如果包含該Activity(Activity2)的Task已經(jīng)運(yùn)行的話,他會(huì)在該運(yùn)行的Task中重新創(chuàng)建。
經(jīng)過上述的介紹,用下面的表格來進(jìn)行一個(gè)簡(jiǎn)單的總結(jié),如表1-1所示。
表1-1 Activity4種啟動(dòng)模式對(duì)比
區(qū)別 |
是否允許多個(gè)實(shí)例 |
如何決定所屬Task |
是否每次都生成新實(shí)例 |
是否允許其他Activity存在于本Task內(nèi) |
standard |
可被多次實(shí)例化,同一個(gè)Task的不同的實(shí)例可位于不同的Task中,每個(gè)Task也可包含多個(gè)實(shí)例 |
存放于Start
Activity()的 Task。除非設(shè)置 FLAG_ACTIVITY _NEW_TASK標(biāo)記 |
是 |
允許 |
singleTop |
同standard |
同standard |
如果寄存Activity的棧頂為該Activity,則直接用該Activity處理;否則,創(chuàng)建新實(shí)例 |
允許 |
singleTask |
不能有多個(gè)實(shí)例。由于該模式下Activity總是位于棧頂,所以Actvity在同一個(gè)設(shè)備里多只有一個(gè)實(shí)例 |
放入新的Task內(nèi),并且位于該Task的根 |
只有在第一次才創(chuàng)建新的實(shí)例,其他情況復(fù)用該Activity |
允許。如果存放singleTask的棧寄存在Task內(nèi),響應(yīng)一個(gè)Intent時(shí),如果singleTask位于棧頂,則處理Intent,否則會(huì)丟失Intent,但該Task會(huì)處于前臺(tái) |
singleInstance |
同singleTask |
同singleTask |
同singleTask |
不允許 |