Activity的launchMode
launchMode,通俗點(diǎn)說,就是定義了Activity應(yīng)該如何被launch的。那么這幾種模式的區(qū)別以及應(yīng)用場景,會有何不同呢?谷歌是基于什么原因設(shè)計這幾種模式的呢?這幾種模式背后的工作原理是什么呢?
任務(wù)和返回棧
在講解launchMode之前,先說說任務(wù)(Task)和返回棧(Back Stack,有些譯作回退棧、任務(wù)棧)這兩個概念。
A task is a collection of activities that users interact with when performing a certain job. The activities are arranged in a stack—the back stack—in the order in which each activity is opened.
任務(wù)是指當(dāng)完成一個特定的工作時與用戶交互的一系列Activity。這些Activity按照打開的順序存放在一個棧中,即返回棧。
通過定義可以知道,Activity會被按照打開的順序存放。不難猜想,這種存放方式,是為了方便回退操作,也就不難解釋為什么要用棧去存放。
當(dāng)用戶點(diǎn)擊啟動app的時候,這個app的返回棧就會跑到前臺,如果這個返回棧不存在的話,就會創(chuàng)建一個。當(dāng)前Activity啟動另一個Activity的時候,新的Activity就會入棧,在棧頂。如果用戶點(diǎn)擊返回按鈕,當(dāng)前的Activity就會出棧并銷毀,之前的Activity就會被resume,如果棧為空,就會被銷毀掉。棧中的Activity永遠(yuǎn)都不會被重新排序。
返回棧根據(jù)是否在前臺,可以分為在前臺顯示的返回棧,和置于后臺的返回棧。其中,置于后臺的返回棧中所有的Activity都處于stop狀態(tài),用戶可以手動的去切換前后臺的返回棧狀態(tài)。
當(dāng)系統(tǒng)內(nèi)存不足時,系統(tǒng)會優(yōu)先銷毀處于后臺的Activity。那么問題來了。后臺銷毀Activity的優(yōu)先級是怎樣的呢?是將一個返回棧中的Activity都銷毀了過后,再去銷毀另一個,還是說,只是單純的按照Activity來銷毀回收呢?
任務(wù)管理
任務(wù)以及返回棧的管理,可以通過一系列的參數(shù)設(shè)置來進(jìn)行,包括我們本文講解的launchMode,也是任務(wù)管理的一種方式。
taskAffinity
TaskAffinity即任務(wù)相關(guān)性,標(biāo)識一個Activity所需要的返回棧的名字。默認(rèn)情況下是包名。設(shè)置了相同taskAffinity屬性的Activity會被放進(jìn)同一個棧中。一個返回棧的相關(guān)性(affinity)是由這個棧的根Activity的相關(guān)性(affinity)決定的。
taskAffinity屬性主要與singleTask或allowTaskReparenting結(jié)合使用,在其他情況下,這個屬性沒有作用。這是為什么呢?
allowTaskReparenting
它的主要作用是Activity的遷移,從一個棧遷移到另一個棧,這個遷移跟Activity的taskAffinity有關(guān)。
clearTaskOnLaunch
這個屬性用來清除回退棧中除了根Activity的所有Activity,只對根Activity起作用。當(dāng)設(shè)置為true時,每次重新進(jìn)入app,只會看到根Activity。
finishOnTaskLaunch
這個屬性與clearTaskOnLaunch相反,它是將本Activity移除出去,而不影響其他的Activity。
alwaysRetainTaskState
這個屬性的作用是保存返回棧的狀態(tài),只對根Activity起作用。正常情況下,系統(tǒng)清理一個返回棧,會將根Activity之上的所有Activity都清除掉。設(shè)置該屬性后,系統(tǒng)會保存當(dāng)前的狀態(tài)。
啟動模式
啟動模式主要的作用是什么呢?根據(jù)上面對任務(wù)及返回棧的介紹,它的作用是定義,一個新的Activity實(shí)例如何與當(dāng)前的任務(wù)相關(guān)聯(lián)。它本身是任務(wù)的管理方式。
啟動模式有兩種定義方式,manifest里定義和intent flag的方式。一種是類似配置式的,一種是代碼層面的??梢源笾峦茰y,肯定是帶么層面的優(yōu)先級高一些,但是代碼方式劣處就是不啟動Activity就無法設(shè)置。Android中這種一般提供動態(tài)以及靜態(tài)方式的,套路都大致相同,一些區(qū)別各種優(yōu)劣等。
其中manifest設(shè)置與intent flag中都包含對方?jīng)]有的方式。這也是兩者的一個區(qū)別。
launchMode
此處的launchMode專指Activity的launchMode屬性。其中有四種方式,這四種方式想必大家也都很清楚了,在這里我不詳細(xì)展開了。
standard
最常見的一種模式,Activity的默認(rèn)模式,每次啟動該模式的Activity,都會被重新創(chuàng)建,可以從屬不同的任務(wù),也可以在一個任務(wù)中被創(chuàng)建多次。
它的應(yīng)用場景特別廣泛, 一般不是特殊需求的話,都會去使用這種模式。
singleTop
如果在當(dāng)前任務(wù)的棧頂,系統(tǒng)會調(diào)用Activity的onNewIntent()方法而不是重新創(chuàng)建一個新的實(shí)例。當(dāng)用戶點(diǎn)擊返回鍵時,當(dāng)前Activity會被出棧,而不是會退到onNewIntent()之前的狀態(tài)。
它的應(yīng)用場景也有一些。例如搜索頁面,每次打開,搜索一些結(jié)果,點(diǎn)擊詳情頁面,然后繼續(xù)搜索。在比方說,通過通知打開的頁面,如果該頁面存在,則更新,如果不存在,則創(chuàng)建。
singleTask
該模式只允許系統(tǒng)中存在一個該Activity的實(shí)例,如果當(dāng)前實(shí)例不存在,則創(chuàng)建,如果已經(jīng)存在,則將該實(shí)例之上的Activity全部出棧,走onNewIntent()。
singleTask適合作為程序入口點(diǎn),當(dāng)通過其他方式調(diào)用app時候,不會反復(fù)創(chuàng)建主頁面。例如一般情況下的MainActivity,其他app調(diào)用的時候。
singleInstance
這種模式與singleTask十分類似,區(qū)別在于,持有該Activity的任務(wù)中只能包含一個Activity即它本身。
singleInstance適合需要與程序分離開的頁面,例如鬧鐘的響鈴界面,與鬧鐘的設(shè)置相分離。再例如系統(tǒng)的撥號界面。
Intent flags
此處討論的是通過代碼方式進(jìn)行設(shè)置,常見的有如下三種方式。
FLAG_ACTIVITY_NEW_TASK
使用一個新的返回棧來啟動Activity,跟上面討論的singleTask類似
FLAG_ACTIVITY_SINGLE_TOP
跟上面討論的singleTop類似
FLAG_ACTIVITY_CLEAR_TOP
這種方式是上面討論的launchMode中不存在的,它與singleTop的區(qū)別是,當(dāng)已存在該實(shí)例了,會將它之上的Activity都出棧。
它經(jīng)常與FLAG_ACTIVITY_NEW_TASK組合使用,可以達(dá)到singleTask的作用。
回到問題
幾種模式的區(qū)別以及應(yīng)用場景,會有何不同呢?
答案見上面關(guān)于launchMode
谷歌是基于什么原因設(shè)計這幾種模式的呢?
關(guān)于這個問題,我們先倒著來推理,即從使用場景去考慮,一般狀況下,我們打開一個頁面,不在意是否是唯一,這個是最常見的需求,因此有了standard模式,這種也是默認(rèn)的模式。當(dāng)我們用搜索頁面,當(dāng)最頂層是搜索頁面的時候,我不希望再打開一個搜索頁面,于是有了singleTop模式。當(dāng)從其他App調(diào)用我們的app的時候,我只希望只顯示一個主頁面時,于是有了singleTask。關(guān)于singleInstance模式,則是希望與當(dāng)前的頁面分離。
但是,我覺得谷歌并不能列舉出所有的場景,例如,我希望打開一個頁面,記錄當(dāng)前的路徑,例如a->b->c,這種場景下,四種模式里面沒有包含。
如果從正面去推導(dǎo)的話,幾種啟動模式是任務(wù)及返回棧的管理。根據(jù)在棧中的狀態(tài),大致可以分為如下幾類:
- 最常見的出棧入棧(standard)
- 當(dāng)前棧中唯一(singleTask)
- 全局唯一(singleInstance)
- 棧頂唯一(singleTop)
是不是很明晰了,有沒有其他的出現(xiàn)形式?肯定有的,例如棧底唯一,棧中唯一。但是這種方式可以等同于當(dāng)前棧中唯一啊。
我們是否可以推導(dǎo)出,谷歌是根據(jù)唯一性,來將啟動模式分為這幾種呢?intent flags則作為輔助的一些操作,例如部分出棧等等。當(dāng)然這些也只是我的推測,不一定準(zhǔn)確,哈哈。
這幾種模式背后的工作原理是什么呢?
見任務(wù)及返回棧
內(nèi)存回收的方式,是以Activity還是以任務(wù)作為基準(zhǔn)回收?
目前已知的狀況時,如果返回棧置于后臺,當(dāng)內(nèi)存不足的時候,如果不設(shè)置alwaysRetainTaskState屬性的話,會將除了根Activity的所有Activity銷毀掉??梢源_定是以返回棧為基準(zhǔn)來進(jìn)行回收。
taskAffinity屬性為什么與singleTask一起使用才生效?
可以將Activity的launchMode根據(jù)是否在棧中唯一分為兩類
- standard、singleTop
- singleTask、singleInstance
第一類因?yàn)槠湮ㄒ恍?,肯定是與taskAffinity不兼容的。singleInstance創(chuàng)建的棧中只能包含本身,默認(rèn)情況下都會單獨(dú)創(chuàng)建一個棧,指定與否都會單獨(dú)創(chuàng)建,因此設(shè)置沒有意義。而singleTask則是當(dāng)前棧中唯一,適合作為根Activity,創(chuàng)建一個新的棧,這也是為什么taskAffinity只能對根Activity起作用的緣故。
最后
我寫的內(nèi)容不一定正確,一些問題的解釋也是根據(jù)我看到的資料來推到出來的,例如Activity為什么會有四種啟動模式,如果大家有準(zhǔn)確地答案,希望告知。另外,文中錯誤的地方,也希望指正。
最后,感謝大家的瀏覽,希望對您有所幫助。