Activity的launchMode
launchMode集币,通俗點(diǎn)說,就是定義了Activity應(yīng)該如何被launch的。那么這幾種模式的區(qū)別以及應(yīng)用場(chǎng)景崔慧,會(huì)有何不同呢?谷歌是基于什么原因設(shè)計(jì)這幾種模式的呢穴墅?這幾種模式背后的工作原理是什么呢惶室?
任務(wù)和返回棧
在講解launchMode之前,先說說任務(wù)(Task)和返回棧(Back Stack玄货,有些譯作回退棧拇涤、任務(wù)棧)這兩個(gè)概念。
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)完成一個(gè)特定的工作時(shí)與用戶交互的一系列Activity誉结。這些Activity按照打開的順序存放在一個(gè)棧中鹅士,即返回棧。
通過定義可以知道惩坑,Activity會(huì)被按照打開的順序存放掉盅。不難猜想,這種存放方式以舒,是為了方便回退操作趾痘,也就不難解釋為什么要用棧去存放。
當(dāng)用戶點(diǎn)擊啟動(dòng)app的時(shí)候蔓钟,這個(gè)app的返回棧就會(huì)跑到前臺(tái)永票,如果這個(gè)返回棧不存在的話,就會(huì)創(chuàng)建一個(gè)滥沫。當(dāng)前Activity啟動(dòng)另一個(gè)Activity的時(shí)候侣集,新的Activity就會(huì)入棧,在棧頂兰绣。如果用戶點(diǎn)擊返回按鈕世分,當(dāng)前的Activity就會(huì)出棧并銷毀,之前的Activity就會(huì)被resume缀辩,如果棧為空臭埋,就會(huì)被銷毀掉踪央。棧中的Activity永遠(yuǎn)都不會(huì)被重新排序。
返回棧根據(jù)是否在前臺(tái)瓢阴,可以分為在前臺(tái)顯示的返回棧畅蹂,和置于后臺(tái)的返回棧。其中荣恐,置于后臺(tái)的返回棧中所有的Activity都處于stop狀態(tài)魁莉,用戶可以手動(dòng)的去切換前后臺(tái)的返回棧狀態(tài)。
當(dāng)系統(tǒng)內(nèi)存不足時(shí)募胃,系統(tǒng)會(huì)優(yōu)先銷毀處于后臺(tái)的Activity旗唁。那么問題來了。后臺(tái)銷毀Activity的優(yōu)先級(jí)是怎樣的呢痹束?是將一個(gè)返回棧中的Activity都銷毀了過后检疫,再去銷毀另一個(gè),還是說祷嘶,只是單純的按照Activity來銷毀回收呢屎媳?
任務(wù)管理
任務(wù)以及返回棧的管理,可以通過一系列的參數(shù)設(shè)置來進(jìn)行论巍,包括我們本文講解的launchMode烛谊,也是任務(wù)管理的一種方式。
taskAffinity
TaskAffinity即任務(wù)相關(guān)性嘉汰,標(biāo)識(shí)一個(gè)Activity所需要的返回棧的名字丹禀。默認(rèn)情況下是包名。設(shè)置了相同taskAffinity屬性的Activity會(huì)被放進(jìn)同一個(gè)棧中鞋怀。一個(gè)返回棧的相關(guān)性(affinity)是由這個(gè)棧的根Activity的相關(guān)性(affinity)決定的双泪。
taskAffinity屬性主要與singleTask或allowTaskReparenting結(jié)合使用,在其他情況下密似,這個(gè)屬性沒有作用焙矛。這是為什么呢?
allowTaskReparenting
它的主要作用是Activity的遷移残腌,從一個(gè)棧遷移到另一個(gè)棧村斟,這個(gè)遷移跟Activity的taskAffinity有關(guān)。
clearTaskOnLaunch
這個(gè)屬性用來清除回退棧中除了根Activity的所有Activity抛猫,只對(duì)根Activity起作用蟆盹。當(dāng)設(shè)置為true時(shí),每次重新進(jìn)入app邑滨,只會(huì)看到根Activity日缨。
finishOnTaskLaunch
這個(gè)屬性與clearTaskOnLaunch相反,它是將本Activity移除出去掖看,而不影響其他的Activity匣距。
alwaysRetainTaskState
這個(gè)屬性的作用是保存返回棧的狀態(tài),只對(duì)根Activity起作用哎壳。正常情況下毅待,系統(tǒng)清理一個(gè)返回棧,會(huì)將根Activity之上的所有Activity都清除掉归榕。設(shè)置該屬性后尸红,系統(tǒng)會(huì)保存當(dāng)前的狀態(tài)。
啟動(dòng)模式
啟動(dòng)模式主要的作用是什么呢刹泄?根據(jù)上面對(duì)任務(wù)及返回棧的介紹外里,它的作用是定義,一個(gè)新的Activity實(shí)例如何與當(dāng)前的任務(wù)相關(guān)聯(lián)特石。它本身是任務(wù)的管理方式盅蝗。
啟動(dòng)模式有兩種定義方式,manifest里定義和intent flag的方式姆蘸。一種是類似配置式的墩莫,一種是代碼層面的〕逊螅可以大致推測(cè)狂秦,肯定是帶么層面的優(yōu)先級(jí)高一些,但是代碼方式劣處就是不啟動(dòng)Activity就無(wú)法設(shè)置推捐。Android中這種一般提供動(dòng)態(tài)以及靜態(tài)方式的裂问,套路都大致相同,一些區(qū)別各種優(yōu)劣等牛柒。
其中manifest設(shè)置與intent flag中都包含對(duì)方?jīng)]有的方式愕秫。這也是兩者的一個(gè)區(qū)別。
launchMode
此處的launchMode專指Activity的launchMode屬性焰络。其中有四種方式戴甩,這四種方式想必大家也都很清楚了,在這里我不詳細(xì)展開了闪彼。
standard
最常見的一種模式甜孤,Activity的默認(rèn)模式,每次啟動(dòng)該模式的Activity畏腕,都會(huì)被重新創(chuàng)建缴川,可以從屬不同的任務(wù),也可以在一個(gè)任務(wù)中被創(chuàng)建多次描馅。
它的應(yīng)用場(chǎng)景特別廣泛把夸, 一般不是特殊需求的話,都會(huì)去使用這種模式铭污。
singleTop
如果在當(dāng)前任務(wù)的棧頂恋日,系統(tǒng)會(huì)調(diào)用Activity的onNewIntent()方法而不是重新創(chuàng)建一個(gè)新的實(shí)例膀篮。當(dāng)用戶點(diǎn)擊返回鍵時(shí),當(dāng)前Activity會(huì)被出棧岂膳,而不是會(huì)退到onNewIntent()之前的狀態(tài)誓竿。
它的應(yīng)用場(chǎng)景也有一些。例如搜索頁(yè)面谈截,每次打開筷屡,搜索一些結(jié)果,點(diǎn)擊詳情頁(yè)面簸喂,然后繼續(xù)搜索毙死。在比方說,通過通知打開的頁(yè)面喻鳄,如果該頁(yè)面存在扼倘,則更新,如果不存在诽表,則創(chuàng)建唉锌。
singleTask
該模式只允許系統(tǒng)中存在一個(gè)該Activity的實(shí)例,如果當(dāng)前實(shí)例不存在竿奏,則創(chuàng)建袄简,如果已經(jīng)存在,則將該實(shí)例之上的Activity全部出棧泛啸,走onNewIntent()绿语。
singleTask適合作為程序入口點(diǎn),當(dāng)通過其他方式調(diào)用app時(shí)候候址,不會(huì)反復(fù)創(chuàng)建主頁(yè)面吕粹。例如一般情況下的MainActivity,其他app調(diào)用的時(shí)候岗仑。
singleInstance
這種模式與singleTask十分類似匹耕,區(qū)別在于,持有該Activity的任務(wù)中只能包含一個(gè)Activity即它本身荠雕。
singleInstance適合需要與程序分離開的頁(yè)面稳其,例如鬧鐘的響鈴界面,與鬧鐘的設(shè)置相分離炸卑。再例如系統(tǒng)的撥號(hào)界面既鞠。
Intent flags
此處討論的是通過代碼方式進(jìn)行設(shè)置,常見的有如下三種方式盖文。
FLAG_ACTIVITY_NEW_TASK
使用一個(gè)新的返回棧來啟動(dòng)Activity嘱蛋,跟上面討論的singleTask類似
FLAG_ACTIVITY_SINGLE_TOP
跟上面討論的singleTop類似
FLAG_ACTIVITY_CLEAR_TOP
這種方式是上面討論的launchMode中不存在的,它與singleTop的區(qū)別是,當(dāng)已存在該實(shí)例了洒敏,會(huì)將它之上的Activity都出棧龄恋。
它經(jīng)常與FLAG_ACTIVITY_NEW_TASK組合使用,可以達(dá)到singleTask的作用桐玻。
回到問題
幾種模式的區(qū)別以及應(yīng)用場(chǎng)景篙挽,會(huì)有何不同呢荆萤?
答案見上面關(guān)于launchMode
谷歌是基于什么原因設(shè)計(jì)這幾種模式的呢镊靴?
關(guān)于這個(gè)問題,我們先倒著來推理链韭,即從使用場(chǎng)景去考慮偏竟,一般狀況下,我們打開一個(gè)頁(yè)面敞峭,不在意是否是唯一踊谋,這個(gè)是最常見的需求,因此有了standard模式旋讹,這種也是默認(rèn)的模式殖蚕。當(dāng)我們用搜索頁(yè)面,當(dāng)最頂層是搜索頁(yè)面的時(shí)候沉迹,我不希望再打開一個(gè)搜索頁(yè)面睦疫,于是有了singleTop模式。當(dāng)從其他App調(diào)用我們的app的時(shí)候鞭呕,我只希望只顯示一個(gè)主頁(yè)面時(shí)蛤育,于是有了singleTask。關(guān)于singleInstance模式葫松,則是希望與當(dāng)前的頁(yè)面分離。
但是,我覺得谷歌并不能列舉出所有的場(chǎng)景祝懂,例如腾么,我希望打開一個(gè)頁(yè)面,記錄當(dāng)前的路徑珊擂,例如a->b->c圣勒,這種場(chǎng)景下,四種模式里面沒有包含未玻。
如果從正面去推導(dǎo)的話灾而,幾種啟動(dòng)模式是任務(wù)及返回棧的管理。根據(jù)在棧中的狀態(tài)扳剿,大致可以分為如下幾類:
- 最常見的出棧入棧(standard)
- 當(dāng)前棧中唯一(singleTask)
- 全局唯一(singleInstance)
- 棧頂唯一(singleTop)
是不是很明晰了旁趟,有沒有其他的出現(xiàn)形式?肯定有的,例如棧底唯一锡搜,棧中唯一橙困。但是這種方式可以等同于當(dāng)前棧中唯一啊。
我們是否可以推導(dǎo)出耕餐,谷歌是根據(jù)唯一性凡傅,來將啟動(dòng)模式分為這幾種呢?intent flags則作為輔助的一些操作肠缔,例如部分出棧等等夏跷。當(dāng)然這些也只是我的推測(cè),不一定準(zhǔn)確明未,哈哈槽华。
這幾種模式背后的工作原理是什么呢?
見任務(wù)及返回棧
內(nèi)存回收的方式趟妥,是以Activity還是以任務(wù)作為基準(zhǔn)回收猫态?
目前已知的狀況時(shí),如果返回棧置于后臺(tái)披摄,當(dāng)內(nèi)存不足的時(shí)候亲雪,如果不設(shè)置alwaysRetainTaskState屬性的話,會(huì)將除了根Activity的所有Activity銷毀掉疚膊∫逶可以確定是以返回棧為基準(zhǔn)來進(jìn)行回收。
taskAffinity屬性為什么與singleTask一起使用才生效酿联?
可以將Activity的launchMode根據(jù)是否在棧中唯一分為兩類
- standard终息、singleTop
- singleTask、singleInstance
第一類因?yàn)槠湮ㄒ恍哉耆茫隙ㄊ桥ctaskAffinity不兼容的周崭。singleInstance創(chuàng)建的棧中只能包含本身,默認(rèn)情況下都會(huì)單獨(dú)創(chuàng)建一個(gè)棧喳张,指定與否都會(huì)單獨(dú)創(chuàng)建续镇,因此設(shè)置沒有意義。而singleTask則是當(dāng)前棧中唯一销部,適合作為根Activity摸航,創(chuàng)建一個(gè)新的棧,這也是為什么taskAffinity只能對(duì)根Activity起作用的緣故舅桩。
最后
我寫的內(nèi)容不一定正確酱虎,一些問題的解釋也是根據(jù)我看到的資料來推到出來的,例如Activity為什么會(huì)有四種啟動(dòng)模式擂涛,如果大家有準(zhǔn)確地答案读串,希望告知。另外,文中錯(cuò)誤的地方恢暖,也希望指正排监。
最后,感謝大家的瀏覽杰捂,希望對(duì)您有所幫助舆床。