Android啟動模式完全解析(下)

在這篇文章中扫茅,我會繼續(xù)跟大家分享有關(guān)于Android中啟動模式的相關(guān)知識。當然非迹,如果對這個啟動模式還不完全了解或者沒有聽過的話抡谐,可以先看看我之前寫的有關(guān)于這個知識點的入門篇Android的啟動模式(上)。好了俏蛮,言歸正傳撑蚌,在上一篇已經(jīng)介紹過,activity在棧中默認不能重排搏屑,因此争涌,應(yīng)用中的一個activity可能被多次實例化并且壓入同一個棧中,如圖所示:

back_stack

如果此時使用back鍵返回辣恋,activity的每個實例都將會按照打開的順序重新出現(xiàn)亮垫。這勢必會導致用戶生體驗效果,因此要改變這種現(xiàn)象或者解決上篇末尾提到的問題伟骨,對啟動模式的了解必不可少饮潦,當然,若想了解得更加透徹的話底靠,歡迎訪問官方文檔:Tasks and Back Stack害晦。

定義啟動模式

總的來說特铝,啟動模式?jīng)Q定了你的activity和task的關(guān)聯(lián)性暑中。當一個activity啟動的時候壹瘟,有兩種方式指定它與task的關(guān)聯(lián):使用manifest文件和使用intent flag。當intent的flag和manifest所指定的啟動模式發(fā)生沖突的時候鳄逾,此時就以intent flag指定的模式為準稻轨。


  1. 使用manifest清單文件設(shè)置啟動模式

    通過在manifest文件<activity>中添加launchMode屬性來指定啟動模式:

    • standard,默認的LaunchMode雕凹,也是最容易理解的殴俱。如果某個Activity使用該 LaunchMode, 當這個Activity啟動時枚抵,系統(tǒng)會創(chuàng)建一個該Activity的新的實例线欲,并且傳遞 一個intent給它。該 Activity可以被實例化多次汽摹,各個實例可以屬于不同的Task李丰,一個Task 中也可以存在多個實例。

    • singleTop逼泣,如果這個Activity有一個實例已經(jīng)存在于當前Task的頂部趴泌,那么系統(tǒng)就會傳 遞一 個intent給這個實例的onNewIntent()方法,而不會去重新創(chuàng)建一個新的Activity實例拉庶。 這個 Activity也可以被實例化多次嗜憔,每個實例可以屬于不同的task,但只有當Back Stack棧頂 的Activity實例不是該Activity的實例時氏仗,一個task中也可以存在多個實例吉捶。應(yīng)該注意的是,
      當一個Activity的新實例創(chuàng)建完畢后皆尔,用戶可以按返回鍵返回前一個activity帚稠。但是當 Activity已有實例正在處理剛到達的intent時,用戶無法用返回鍵回到onNewIntent()中 intent到來之前的Activity 狀態(tài)床佳。

    • singleTask滋早,系統(tǒng)創(chuàng)建一個新的Task,并且實例化這個Activity作為這個Task的根 Activity砌们。然而杆麸,若這個Activity已經(jīng)存在了一個實例在一個Task中,那么系統(tǒng)就會將這個 Intent傳遞到這個Activity的onNewIntent()方法浪感,而不是去重新創(chuàng)建一個實例昔头。同一個時 間,只允許存在一個這樣的Activity影兽。注意的是揭斧,雖然系統(tǒng)創(chuàng)建了一個新的Task,但是只要按 下返回鍵還是會回到原來的Activity

    • singleInstance,和"singleTask"類似讹开,不同的是盅视,系統(tǒng)不會再該activity實例的task中,啟動任何其他Activity到這個task中旦万。這個Activity是它所在的task中唯一的成員闹击。任何有這個activity啟動的Activity都會放入到另外一個task中。


對于返回處理成艘,不管activity是在一個新的task啟動赏半,還是在當前task中啟動,只要一按下返回鍵淆两,就會返回到之前的那個activity中断箫。但是也是存在一種情況例外,就是當你啟動一個啟動模式設(shè)為singleTask的Activity時秋冰,如果這個activity在一個后臺task中存在實例瑰枫,那個這整個task將會被放置到前臺,這時候丹莲,back stack就會包含這個task中所有的activities光坝,并且它們都是放在棧頂。如下圖:

figure
  1. 使用Intent的flag設(shè)置啟動模式

    當你啟動一個Activity時甥材,你也可以動態(tài)的設(shè)置intent的flag盯另,然后通過startActivity()方法啟動activity,從而修改其啟動的activity與它的task的關(guān)聯(lián)模式洲赵。具體可以使用的flag有:

    • FLAG_ACTIVITY_NEW_TASK:對應(yīng)之前的“singleTask”鸳惯,在新的task中啟動activity,如果一個你需要的activity的task已經(jīng)存在叠萍,則將它推向前臺芝发,恢復其上一個狀態(tài),它通過onNewIntent()收到這個新的intent苛谷。

    • FLAG_ACTIVITY_SINGLE_TOP:對應(yīng)之前的“singleTop”,如果被啟動的activity是當前頂部的activity辅鲸,則已經(jīng)存在的實例會收到onIntent(),而不會重新去創(chuàng)建這個實例。

    • FLAG_ACTIVITY_CLEAR_TOP:這個行為在launchMode屬性中沒對應(yīng)的屬性值腹殿,若被啟動的activity已經(jīng)在當前task中運行独悴,則不會創(chuàng)建它的新實例,而是的銷毀在它之上的其他所有的activities锣尉,然后通過 onNewIntent()傳遞一個新的intent給這個恢復了的activity刻炒,它一般會與FLAG_ACTIVITY_NEW_TASK一起使用。值得注意的是自沧,如果activity的啟動模式是"standard"坟奥,它自己也將被移除,然后一個新的實例將被啟動。這是因為當啟動模式是"standard"時爱谁,為了接收新的intent必須創(chuàng)建新的實例晒喷。


任務(wù)共用性的處理(Handling affinities)

一般來說,singleTask就是開啟一個新的Task管行,但是在實際使用過程中厨埋,我們有時會發(fā)現(xiàn)邪媳,有時候并不是這樣的捐顷,這是因為我們定義了affinities,也就是任務(wù)公用性。

affinity定義了一個Activity將被分配到哪一個Task中雨效。默認情況下迅涮,同一個app中得所有activity有一個同樣的affinity,因此徽龟,默認情況下同一個應(yīng)用程序中得所有activity都在同一個task中叮姑。一個Task的affinity由這個Task的根Actiivty決定。然而据悔,我們可以修改Activity默認的affinity传透,這樣,不同應(yīng)用程序的Activity可以共用同樣的affinity极颓,或者同一個程序的不同Activity分配不同的affinity朱盐。一個應(yīng)用程序默認的affinity就是應(yīng)用程序的包名,所以菠隆,如果我們想定義一個不同的affinity兵琳,必須和默認的affinity不同。我們可以通過<application>中得android:taskAffinity修改整個程序的affinity骇径,也可以通過<activity>的android:taskAffinity對單個Activity的affinity修改躯肌。


而affinity的使用通常有以下兩種情況,

  1. 當android:launchMode是singleTask或者Intent中包含F(xiàn)LAG_ACTIVITY_NEW_TASK:

    默認情況下破衔,我們調(diào)用startActivity()清女,會實例化一個Activity,放入到與調(diào)用者相同的task晰筛。但是如果這個Activity的的啟動模式是singleTask校仑,或者啟動它的Intent包含了
    FLAG_ACTIVITY_NEW_TASK時,系統(tǒng)會進行如下的步驟:

    • 判斷這個Activity有沒有實例已經(jīng)存在了传惠,有的話迄沫,直接傳遞Intent到它的onNewIntent()方法中。
    • 如果不存在卦方,系統(tǒng)查找是否有與這個Activity相同affinity的Task已經(jīng)存在羊瘩,如果存在,那么就將這個Activity啟動到這個Task中。
    • 如果不存在這樣的Task尘吗,那么系統(tǒng)就會創(chuàng)建一個新的Task逝她,并且將這個Activity啟動這個Task中,作為根Activity睬捶。

    因此黔宛,從現(xiàn)在看來,只是單純的用singleTask指定Activity擒贸,是不能開辟一個新的Task的臀晃,因為我們并沒有給他指定affinity。而官方文檔對于singleTask的描述介劫,都是基于我們使用了不同的affinity的前提下徽惋,只不過是省略了這個描述。所以座韵,我們要明白险绘,singleTask的正確用法,應(yīng)該是結(jié)合affinity使用的誉碴。

  2. 當一個Activity設(shè)置allowTaskReparenting屬性為true:

    這個屬性定義了一個Activity宦棺,表示是否可以從一個啟動它的task,切換到與它相同affinity的task中里去(當這個task切換到前臺的時候)黔帕。true表示可以移動代咸,false表示它必須呆在啟動他得task里。
    通常情況下蹬屹,當一個Activity啟動了侣背,那么它就會存在于啟動它的task中,并且在整個生命周期中都留在這個task中慨默。但是贩耐,我們可以通過這個屬性,做出如下改變厦取,當這個Activity當前的Task處于后臺潮太,這個時候如果有一個該Activity具有相同affinity的Task被啟動到前臺,那么這個Activity就可以從它之前的Task虾攻,移動到這個新的Task顯示铡买。
    通常,它的作用是將app中得Activity與app的main task結(jié)合起來霎箍,舉個例子奇钞,如下:
    有一個e-mail程序,他需要調(diào)用瀏覽器程序的某個Activity(假設(shè)為Activity A)來顯示一些數(shù)據(jù)漂坏,這個Activity A的該屬性設(shè)置為true【鞍#現(xiàn)在媒至,e-mail程序調(diào)用了這個Activity A,在用戶看來谷徙,好像這個Activity A就是e-mial程序的一部分拒啰,因為這個Activity A和這個e-mail程序在同一個task中。現(xiàn)在將e-mail退出到后臺完慧,啟動瀏覽器程序谋旦,因為Activity A和瀏覽器程序有相同的affinity,所以Activity A從e-mail程序的Task移動到瀏覽器程序的Task屈尼,并顯示在前臺册着。當我們下次再啟動e-mail程序時,Activity A就不會存在鸿染,因為他已經(jīng)移動到瀏覽器程序的Task里去了指蚜。


清理Back Stack

如果用戶離開一個task很久乞巧,系統(tǒng)就會清理這個task中除了根activity之外的所有activities涨椒。當用戶返回到這個task,只有根activity會被恢復绽媒。但是我們可以設(shè)置一些activity的屬性蚕冬,用來改變這一行為:

  • alwaysRetainTaskState

    如果這個屬性在task的根activity中被設(shè)置為true,那么上面描述的默認行為不會發(fā)生是辕,即便過了很長時間囤热,task仍將會保持所有的activities。

  • clearTaskOnLaunch

    如果這個屬性在task的根activity中被設(shè)置為true获三,每次用戶離開這個task旁蔼,整個task都會被清到只剩根activity,這樣用戶只會永遠返回到它最初的狀態(tài)疙教,即便離開的時間很短棺聊。

  • finishOnTaskLaunch

    這個屬性和上一個很像,不同的是贞谓,它只作用于單個activity限佩,而不是整個task。它可以引起任何activity離開裸弦,包括根activity祟同。當它被設(shè)置為true時,這個activity只在當前會話中屬于這個task理疙,如果用戶離開后再返回晕城,它也不會再出現(xiàn)。

開啟一個Task

我們可以通過一個Activity指定一個intent過濾器窖贤,如下面:

<activity ...>
    <intent-filter ... >
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.inp tent.category.LAUNCHER" />
    </intent-filter>
    ...
</activity>

這時這個activity就作為根activity存在于一個task中砖顷,這個activity也是進入這個task的入口點暇矫,同時,它的圖標和標簽也會被顯示在應(yīng)用啟動界面上择吊,這時用戶就可以啟動這個activity并且再次回到這個任務(wù)李根。因此,從這里我們可以看到几睛,要使用“singleTask”與“singleInstance”房轿,就必須這個activity應(yīng)當也有ACTION_MAIN與CATEGORY_LAUNCHER過濾器。因為假如沒有設(shè)置這兩個過濾器的話所森,當一個intent啟動一個"singleTask"的activity,在新的Task中進行初使化囱持,運行一段時間后,用戶突然按上了home鍵回到桌面焕济,此時這個Task就被移到后臺并且不可見纷妆,因為這個activity沒有設(shè)置過濾器,所以不是應(yīng)用啟動的activity晴弃,那么用戶也就無法返回到這個Task中了掩幢。

總結(jié)

今天的分享也差不多接近尾聲了,有關(guān)Android的啟動模式的主要部分的分析也大多涉及到了上鞠。我想际邻,如果大家想要全面地了解Android的啟動模式的話,我希望可以堅持看完這兩篇文章芍阎,我相信世曾,看完后你對Android的啟動模式還有工作棧的理解應(yīng)該有了很大的提高,對activity與Task的操作也會更加得心應(yīng)手谴咸。當然轮听,如果你覺得文章中有什么寫得錯誤或者不了解的地方,歡迎留言交流岭佳,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末血巍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子驼唱,更是在濱河造成了極大的恐慌藻茂,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玫恳,死亡現(xiàn)場離奇詭異辨赐,居然都是意外死亡,警方通過查閱死者的電腦和手機京办,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門掀序,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惭婿,你說我怎么就攤上這事不恭∫侗ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵换吧,是天一觀的道長折晦。 經(jīng)常有香客問我,道長沾瓦,這世上最難降的妖魔是什么满着? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮贯莺,結(jié)果婚禮上风喇,老公的妹妹穿的比我還像新娘。我一直安慰自己缕探,他們只是感情好魂莫,可當我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著爹耗,像睡著了一般耙考。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鲸沮,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天琳骡,我揣著相機與錄音锅论,去河邊找鬼讼溺。 笑死,一個胖子當著我的面吹牛最易,可吹牛的內(nèi)容都是我干的怒坯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼藻懒,長吁一口氣:“原來是場噩夢啊……” “哼剔猿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嬉荆,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤归敬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鄙早,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汪茧,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年限番,在試婚紗的時候發(fā)現(xiàn)自己被綠了舱污。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡弥虐,死狀恐怖扩灯,靈堂內(nèi)的尸體忽然破棺而出媚赖,到底是詐尸還是另有隱情,我是刑警寧澤珠插,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布惧磺,位于F島的核電站,受9級特大地震影響捻撑,放射性物質(zhì)發(fā)生泄漏豺妓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一布讹、第九天 我趴在偏房一處隱蔽的房頂上張望琳拭。 院中可真熱鬧,春花似錦描验、人聲如沸白嘁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽絮缅。三九已至,卻和暖如春呼股,著一層夾襖步出監(jiān)牢的瞬間耕魄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工彭谁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吸奴,地道東北人。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓缠局,卻偏偏與公主長得像则奥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子狭园,可洞房花燭夜當晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容