launchMode,通俗點說,就是定義了Activity應該如何被launch的。那麼這幾種模式的區別以及應用場景,會有何不一樣呢?谷歌是基於什麼緣由設計這幾種模式的呢?這幾種模式背後的工做原理是什麼呢?app
在講解launchMode以前,先說說任務(Task)和返回棧(Back Stack,有些譯做回退棧、任務棧)這兩個概念。post
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.設計
任務是指當完成一個特定的工做時與用戶交互的一系列Activity。這些Activity按照打開的順序存放在一個棧中,即返回棧。orm
經過定義能夠知道,Activity會被按照打開的順序存放。不難猜測,這種存放方式,是爲了方便回退操做,也就不難解釋爲何要用棧去存放。排序
當用戶點擊啓動app的時候,這個app的返回棧就會跑到前臺,若是這個返回棧不存在的話,就會建立一個。當前Activity啓動另外一個Activity的時候,新的Activity就會入棧,在棧頂。若是用戶點擊返回按鈕,當前的Activity就會出棧並銷燬,以前的Activity就會被resume,若是棧爲空,就會被銷燬掉。棧中的Activity永遠都不會被從新排序。生命週期
返回棧根據是否在前臺,能夠分爲在前臺顯示的返回棧,和置於後臺的返回棧。其中,置於後臺的返回棧中全部的Activity都處於stop狀態,用戶能夠手動的去切換先後臺的返回棧狀態。內存
當系統內存不足時,系統會優先銷燬處於後臺的Activity。那麼問題來了。後臺銷燬Activity的優先級是怎樣的呢?是將一個返回棧中的Activity都銷燬了事後,再去銷燬另外一個,仍是說,只是單純的按照Activity來銷燬回收呢?get
任務以及返回棧的管理,能夠經過一系列的參數設置來進行,包括咱們本文講解的launchMode,也是任務管理的一種方式。博客
TaskAffinity即任務相關性,標識一個Activity所須要的返回棧的名字。默認狀況下是包名。設置了相同taskAffinity屬性的Activity會被放進同一個棧中。一個返回棧的相關性(affinity)是由這個棧的根Activity的相關性(affinity)決定的。it
taskAffinity屬性主要與singleTask或allowTaskReparenting結合使用,在其餘狀況下,這個屬性沒有做用。這是爲何呢?
它的主要做用是Activity的遷移,從一個棧遷移到另外一個棧,這個遷移跟Activity的taskAffinity有關。
這個屬性用來清除回退棧中除了根Activity的全部Activity,只對根Activity起做用。當設置爲true時,每次從新進入app,只會看到根Activity。
這個屬性與clearTaskOnLaunch相反,它是將本Activity移除出去,而不影響其餘的Activity。
這個屬性的做用是保存返回棧的狀態,只對根Activity起做用。正常狀況下,系統清理一個返回棧,會將根Activity之上的全部Activity都清除掉。設置該屬性後,系統會保存當前的狀態。
啓動模式主要的做用是什麼呢?根據上面對任務及返回棧的介紹,它的做用是定義,一個新的Activity實例如何與當前的任務相關聯。它自己是任務的管理方式。
啓動模式有兩種定義方式,manifest裏定義和intent flag的方式。一種是相似配置式的,一種是代碼層面的。能夠大體推測,確定是帶麼層面的優先級高一些,可是代碼方式劣處就是不啓動Activity就沒法設置。Android中這種通常提供動態以及靜態方式的,套路都大體相同,一些區別各類優劣等。
其中manifest設置與intent flag中都包含對方沒有的方式。這也是二者的一個區別。
此處的launchMode專指Activity的launchMode屬性。其中有四種方式,這四種方式想必你們也都很清楚了,在這裏我不詳細展開了。
最多見的一種模式,Activity的默認模式,每次啓動該模式的Activity,都會被從新建立,能夠從屬不一樣的任務,也能夠在一個任務中被建立屢次。
它的應用場景特別普遍, 通常不是特殊需求的話,都會去使用這種模式。
若是在當前任務的棧頂,系統會調用Activity的onNewIntent()方法而不是從新建立一個新的實例。當用戶點擊返回鍵時,當前Activity會被出棧,而不是會退到onNewIntent()以前的狀態。
它的應用場景也有一些。例如搜索頁面,每次打開,搜索一些結果,點擊詳情頁面,而後繼續搜索。在比方說,經過通知打開的頁面,若是該頁面存在,則更新,若是不存在,則建立。
該模式只容許系統中存在一個該Activity的實例,若是當前實例不存在,則建立,若是已經存在,則將該實例之上的Activity所有出棧,走onNewIntent()。
singleTask適合做爲程序入口點,當經過其餘方式調用app時候,不會反覆建立主頁面。例如通常狀況下的MainActivity,其餘app調用的時候。
這種模式與singleTask十分相似,區別在於,持有該Activity的任務中只能包含一個Activity即它自己。
singleInstance適合須要與程序分離開的頁面,例如鬧鐘的響鈴界面,與鬧鐘的設置相分離。再例如系統的撥號界面。
此處討論的是經過代碼方式進行設置,常見的有以下三種方式。
使用一個新的返回棧來啓動Activity,跟上面討論的singleTask相似
跟上面討論的singleTop相似
這種方式是上面討論的launchMode中不存在的,它與singleTop的區別是,當已存在該實例了,會將它之上的Activity都出棧。
它常常與FLAG_ACTIVITY_NEW_TASK組合使用,能夠達到singleTask的做用。
幾種模式的區別以及應用場景,會有何不一樣呢?
答案見上面關於launchMode
谷歌是基於什麼緣由設計這幾種模式的呢?
關於這個問題,咱們先倒着來推理,即從使用場景去考慮,通常情況下,咱們打開一個頁面,不在乎是不是惟一,這個是最多見的需求,所以有了standard模式,這種也是默認的模式。當咱們用搜索頁面,當最頂層是搜索頁面的時候,我不但願再打開一個搜索頁面,因而有了singleTop模式。當從其餘App調用咱們的app的時候,我只但願只顯示一個主頁面時,因而有了singleTask。關於singleInstance模式,則是但願與當前的頁面分離。
可是,我以爲谷歌並不能列舉出全部的場景,例如,我但願打開一個頁面,記錄當前的路徑,例如a->b->c,這種場景下,四種模式裏面沒有包含。
若是從正面去推導的話,幾種啓動模式是任務及返回棧的管理。根據在棧中的狀態,大體能夠分爲以下幾類:
是否是很明晰了,有沒有其餘的出現形式?確定有的,例如棧底惟一,棧中惟一。可是這種方式能夠等同於當前棧中惟一啊。
咱們是否能夠推導出,谷歌是根據惟一性,來將啓動模式分爲這幾種呢?intent flags則做爲輔助的一些操做,例如部分出棧等等。固然這些也只是個人推測,不必定準確,哈哈。
這幾種模式背後的工做原理是什麼呢?
見任務及返回棧
內存回收的方式,是以Activity仍是以任務做爲基準回收?
目前已知的情況時,若是返回棧置於後臺,當內存不足的時候,若是不設置alwaysRetainTaskState屬性的話,會將除了根Activity的全部Activity銷燬掉。能夠肯定是以返回棧爲基準來進行回收。
taskAffinity屬性爲何與singleTask一塊兒使用才生效?
能夠將Activity的launchMode根據是否在棧中惟一分爲兩類
第一類由於其惟一性,確定是與taskAffinity不兼容的。singleInstance建立的棧中只能包含自己,默認狀況下都會單首創建一個棧,指定與否都會單首創建,所以設置沒有意義。而singleTask則是當前棧中惟一,適合做爲根Activity,建立一個新的棧,這也是爲何taskAffinity只能對根Activity起做用的緣故。
我寫的內容不必定正確,一些問題的解釋也是根據我看到的資料來推到出來的,例如Activity爲何會有四種啓動模式,若是你們有準確地答案,但願告知。另外,文中錯誤的地方,也但願指正。
最後,感謝你們的瀏覽,但願對您有所幫助。