Activity 的四種啟動模式(launchMode)

一. launchMode的類型

有四種:

  1. standard
  2. singleTop
  3. singleTask
  4. singleInstance

二. 如何設(shè)置?

大多數(shù)情況下, Activity的啟動模式是在AndroidManifest.xml 中直接配置的,具體方法就是找到相應(yīng)的activity,然后添加 ````android:launchMode```標(biāo)簽即可:

<activity
    android:name=".MainActivity"
    android:label="singleTask launchMode"
    android:launchMode="singleTask">

三. 任務(wù)棧

任務(wù)棧,其實(shí)就用來放置和管理 Activity 實(shí)例的容器,之所以叫棧是因?yàn)槔锩娴?Activity 是以棧的形式進(jìn)行放置的,遵循先進(jìn)后出的原則;

Android 在點(diǎn)擊桌面啟動 App 的時(shí)候,系統(tǒng)會為它創(chuàng)建一個Task,用來放置根 Activity, 此時(shí)一般情況下通過根 Activity 啟動的其他 Activity 都會放在這個 Task 中,即新啟動的Activity會被壓入啟動它的那個Activity的棧中,并將新啟動的 Activity放置在棧的頂端顯示它; 當(dāng)用戶按下回退鍵時(shí),就會按從棧頂?shù)綏5撞康捻樞蛞来螌ctivity 在棧中彈出.

總結(jié)一下:

  1. 任務(wù)棧具有后進(jìn)先出的特性,用于存放 Activity 組件;
  2. 啟動一個 App 的時(shí)候,系統(tǒng)會為它默認(rèn)創(chuàng)建 Task,用來放置 Activity;
  3. 默認(rèn)啟動 Activity 會放在同一個 Task 中,新啟動的 Activity 會被壓入啟動它的那個 Activity 的棧中,并且顯示它。當(dāng)用戶連續(xù)按下 Back 鍵時(shí),該 Task 里的 Activity 就會被依次彈出;
  4. 一個 App 中可能不止一個任務(wù)棧 Task,某些特殊情況下,單獨(dú)一個 Actvity 可以獨(dú)享一個任務(wù)棧;
  5. 一個 任務(wù)棧 Task 中的 Activity 可以來自不同的 App,同一個 App 的 Activity 也可能不在一個 Task中;

通過adb命令去查看 Activity 棧的狀態(tài)

adb shell dumpsys activity

//查看當(dāng)前前臺應(yīng)用的任務(wù)棧信息
adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p'
20170622234251793.png

四. launchMode的類型

1. standard

這是 Activity 是默認(rèn)的啟動模式, 如果我們在 AndroidManifest.xml中不明確指出該 Activity 的啟動模式,則會以 standard 的方式啟動, 即可以不用寫配置。
這種模式下,當(dāng)我們發(fā)送一個 intent 啟動該 Activity 后,該 Activity 總是被創(chuàng)建一個新的實(shí)例來工作。 因此,在這種模式下,同一個任務(wù)棧中可以有多個相同的實(shí)例,也允許多個相同Activity疊加.

比如有一個寫郵件的場景,如果同時(shí)發(fā)送5個 standard 模式的 intent 來啟動該寫郵件的 Activity,那么將會啟動5個不同的 Activity,出現(xiàn)5個寫郵件的界面,這顯然是不合適的,正確的方式應(yīng)該是不管我們啟動幾次,應(yīng)該總是有一個寫郵件的界面。

開發(fā)過程中會遇到兩種情況:
這種啟動模式適合絕大多數(shù)Activity
1. 本應(yīng)用內(nèi)打開
新創(chuàng)建的 Activity 實(shí)例放入本應(yīng)用,即發(fā)送 intent 的 task 棧的頂部

2. 不同應(yīng)用間打開  
跨應(yīng)用打開一個activity,的時(shí)候會在 系統(tǒng)的 Recent app 頁面顯示兩個獨(dú)立項(xiàng),但是此時(shí)它們兩個 Activity 仍然是在一個棧中。

3. 跨進(jìn)程調(diào)用啟動
標(biāo)準(zhǔn)啟動模式的 Activity 被跨進(jìn)程調(diào)用,在 Android 5.0之前新啟動的Activity 實(shí)例會放入發(fā)送 Intent 的 Task 的棧的頂部,盡管它們屬于不同的程序; 在 Android 5.0之后,新啟動的 Activity就會放入剛創(chuàng)建的 Task中。

2. singleTop

棧頂復(fù)用模式,如果要啟動 Activity 存在于任務(wù)棧中,并且位于任務(wù)棧的頂部,就不會創(chuàng)建新的 Activity 實(shí)例,而是會調(diào)用 該 Activity 的 onNewIntent() 方法, 避免棧頂?shù)?Activity 被重復(fù)的創(chuàng)建。

使用 singleTop 的 Activity 也可以創(chuàng)建很多個實(shí)例在同一個任務(wù)棧Task中, 與 standard 模式不同的是:

  1. 如果被調(diào)用的目標(biāo) Activity 已經(jīng)位于調(diào)用者 Activity 所在棧的棧頂,則不創(chuàng)建新實(shí)例,而是使用當(dāng)前的 Activity 實(shí)例,并調(diào)用這個 Activity 實(shí)例的 onNewIntent() 方法;

  2. 如果被調(diào)用的 Activity 的實(shí)例已經(jīng)存在但不位于棧頂,那這個被調(diào)用的 Activity 依然會被創(chuàng)建。

跨進(jìn)程調(diào)用啟動
同standard模式,如果是外部程序啟動 singleTop 的 Activity,在 Android 5.0之前新創(chuàng)建的 Activity會位于調(diào)用者的任務(wù)棧Task 中,Android 5.0及以后會放入新的Task中。
  
這種模式多用在通過通知欄或者通知消息啟動 Activity 的時(shí)候, 如果用戶已經(jīng)在當(dāng)前 Activity,此時(shí)用戶如果點(diǎn)擊了一條推送消息后或者從通知欄點(diǎn)擊進(jìn)去也需要跳轉(zhuǎn)到當(dāng)前 Activity,那么為了避免 Activity 的重復(fù)打開,則需要將該 Activity 設(shè)置為 singleTop 并且復(fù)寫 onNewIntent() ;

還有一種情況就是當(dāng)我們連續(xù)點(diǎn)擊一個按鈕的時(shí)候有會啟動好幾個相同的 Activity 的時(shí)候,這時(shí)候可以將 該 Activity 設(shè)置為 singleTop ,連續(xù)點(diǎn)擊的時(shí)候就只能啟動一個 Activity;其實(shí)當(dāng)這個 Activity 啟動比較慢的時(shí)候還是會出現(xiàn)連續(xù)點(diǎn)擊啟動好幾個 Activity 的問題,因?yàn)楫?dāng)該 Activity 一個實(shí)例都還沒有的時(shí)候連續(xù)點(diǎn)擊依然會啟動多個, 如果遇到這種情況建議使用標(biāo)志位去解決。

3. singleTask

棧內(nèi)復(fù)用模式, Activity 只會在任務(wù)棧里面存在一個實(shí)例。如果要啟動的 Activity 在任務(wù)棧 Task 中已經(jīng)存在,就不會創(chuàng)建新的 Activity 實(shí)例,而是復(fù)用這個已經(jīng)存在的 Activity,調(diào)用 onNewIntent() 方法,并且清空這個 Activity 任務(wù)棧之上所有的其他 Activity。

應(yīng)用場景:
App的主頁, 對于大部分應(yīng)用,當(dāng)我們在主界面點(diǎn)擊回退按鈕的時(shí)候都是退出應(yīng)用,那么當(dāng)我們第一次進(jìn)入主界面之后,主界面位于棧底,以后不管我們打開了多少個Activity,只要我們再次回到主界面,都應(yīng)該使用將主界面Activity上所有的Activity移除的方式來讓主界面Activity處于棧頂,而不是往棧頂新加一個主界面Activity的實(shí)例,通過這種方式能夠保證退出應(yīng)用時(shí)所有的Activity都能報(bào)銷毀。

開發(fā)過程中會遇到三種情況:

1. 被啟動的 Activity 在 Task 棧中不存在:
當(dāng)被啟動的 Activity 的啟動模式為 singleTask時(shí),如果該 Activity 在 Task 棧中不存在,則會創(chuàng)建一個新的實(shí)例放在棧頂并啟動;

2. 被啟動的 Activity 在 Task 棧中存在:
如果該 Activity 在 Task 棧中存在,則會將棧中該 Activity 之上的其他 Activity 全部清空,并且調(diào)用該 Activity 的 onNewIntent() 方法;

4. singleInstance

單一實(shí)例模式,與 singleTask 很相似, 具有 singleTask 的全部特性之外,又比singleTask 多了一種特性:

設(shè)置了該模式的 Activity 只能位于一個單獨(dú)的任務(wù)棧中,不能在有其他 Activity , 其他任何從該 Activity 啟動的其他 Activity 都會放到其他的任務(wù)棧中。

singleInstance 模式的 Activity 整個手機(jī)操作系統(tǒng)里面只有一個實(shí)例存在。不同的應(yīng)用去打開這個 Activity 共享公用的同一個 Activity。他會運(yùn)行在自己單獨(dú),獨(dú)立的任務(wù)棧里面,并且任務(wù)棧里面只有他一個實(shí)例存在。

應(yīng)用場景:
呼叫來電界面。這種模式的使用情況比較罕見,在Launcher中可能使用。或者你確定你需要使Activity只有一個實(shí)例。

LaunchMode Flag

Activity 的啟動模式除了在 AndroidManifest 文件中設(shè)置以外,還可以通過 Intent的 Flag 來設(shè)置:

1. FLAG_ACTIVITY_NEW_TASK
使用一個新的任務(wù)棧 Task 來啟動一個 Activity,但啟動的每個Activity都將在一個新的任務(wù)棧 Task 中。該 Flag 通常使用在從Service 中啟動 Activity 的場景,由于Service中并不存在Activity 任務(wù)棧,所以使用該 Flag 來創(chuàng)建一個新的Activity棧,并創(chuàng)建新的 Activity 實(shí)例。

2. FLAG_ACTIVITY_SINGLE_TOP
使用 singletop 模式啟動一個Activity, 當(dāng)這個Activity位于歷史stack的頂端運(yùn)行時(shí),不再創(chuàng)建一個新的Activity實(shí)例;

3. FLAG_ACTIVITY_CLEAR_TOP
銷毀目標(biāo)Activity和它之上的所有Activity,重新創(chuàng)建目標(biāo)Activity

4. FLAG_ACTIVITY_NO_HISTORY
一個 Activity 使用這種模式啟動后,當(dāng)該 Activity 啟動其他Activity后,該 Activity 自己就消失了,不會保留在Activity棧中。

5. FLAG_ACTIVITY_BROUGHT_TO_FRONT
在launchMode中設(shè)置singleTask模式時(shí)系統(tǒng)會設(shè)定。

6. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果設(shè)置,新的Activity不會在最近啟動的Activity的列表中保存。

7. FLAG_ACTIVITY_FORWARD_RESULT
如果設(shè)置,并且這個Intent用于從一個存在的Activity啟動一個新的Activity,那么,這個作為答復(fù)目標(biāo)的Activity將會傳到這個新的Activity中。這種方式下,新的Activity可以調(diào)用setResult(int),并且這個結(jié)果值將發(fā)送給那個作為答復(fù)目標(biāo)的 Activity。

8. FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
這個標(biāo)志一般不由應(yīng)用程序代碼設(shè)置,如果這個Activity是從歷史記錄里啟動的(常按HOME鍵),系統(tǒng)會設(shè)定。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容