淺析Activity啟動(dòng)模式
前言
平常我們啟動(dòng)活動(dòng)的時(shí)候就是直接startActivity或許并沒有注意活動(dòng)的啟動(dòng)模式,默認(rèn)情況下都是以默認(rèn)的啟動(dòng)模式啟動(dòng)。但啟動(dòng)模式有時(shí)候是比較重要的。例如一個(gè)活動(dòng)你想他只啟動(dòng)一次不要有多個(gè)實(shí)例,那么你可能需要把他設(shè)置為singleTask模式。所以有必要了解一下這一些啟動(dòng)模式。同時(shí)要注意一下,啟動(dòng)模式≠啟動(dòng)方式,啟動(dòng)方式是指顯示啟動(dòng)和隱式啟動(dòng),不要混淆,顯示啟動(dòng)和隱式啟動(dòng)后續(xù)我會(huì)有專門的文章講解。
關(guān)于任務(wù)棧簡(jiǎn)介
要了解啟動(dòng)模式,首先要了解一下關(guān)于任務(wù)棧的概念。關(guān)于任務(wù)棧的實(shí)現(xiàn)原理等我在這里就先不說了,這里主要簡(jiǎn)單介紹一下什么是任務(wù)棧。我們啟動(dòng)的活動(dòng)實(shí)例都會(huì)放在一個(gè)叫做任務(wù)棧的東西里面。我們都知道棧是“后進(jìn)先出”的特點(diǎn)。打個(gè)比方,任務(wù)棧就是一個(gè)羽毛球筒,活動(dòng)實(shí)例就是一個(gè)個(gè)羽毛球,后放進(jìn)去的只能先拿出來。所以當(dāng)我們啟動(dòng)一個(gè)app的時(shí)候,就會(huì)自動(dòng)創(chuàng)建一個(gè)任務(wù)棧,然后我們就往里面丟活動(dòng)實(shí)例。當(dāng)我們按返回銷毀活動(dòng)的時(shí)候,這些活動(dòng)就依次從任務(wù)棧里面出來。當(dāng)然,一個(gè)app可以擁有多個(gè)任務(wù)棧,例如使用singleInstence啟動(dòng)的活動(dòng)就是在一個(gè)獨(dú)立的任務(wù)棧中。了解完任務(wù)棧的概念,接下來就可以來看看活動(dòng)的四種啟動(dòng)模式。
解析Activity的四種啟動(dòng)模式
standard
這種是標(biāo)準(zhǔn)啟動(dòng)模式,默認(rèn)就是這種啟動(dòng)模式。每次啟動(dòng)這種啟動(dòng)模式的活動(dòng)的時(shí)候都會(huì)創(chuàng)建一個(gè)新的實(shí)例放入棧中,不管棧中是否已經(jīng)存在相同的實(shí)例。這也是最容易理解的。
singleTop
顧名思義,棧頂是單一實(shí)例的。什么意思呢。假設(shè)你現(xiàn)在啟動(dòng)一個(gè)ActivityA,但是這個(gè)時(shí)候已經(jīng)存在一個(gè)ActivityA實(shí)例在棧頂,那么這個(gè)時(shí)候,就不會(huì)創(chuàng)建新的實(shí)例。但是如果,在非棧頂存在相同的實(shí)例,還是會(huì)創(chuàng)建新的實(shí)例的。例如,現(xiàn)在棧中的活動(dòng)是 ABC,A處于棧頂。然后此時(shí)啟動(dòng)A,是不會(huì)再創(chuàng)建一個(gè)A活動(dòng)出來,而是執(zhí)行A的onNewIntent方法;但是如果此時(shí)啟動(dòng)C活動(dòng),由于棧頂是A不是C,那么還是會(huì)創(chuàng)建一個(gè)新的C實(shí)例出來,此時(shí)的棧情況就是CABC。
singleTask
單一任務(wù)模式。這個(gè)模式的意思是,在該活動(dòng)的啟動(dòng)棧中,只能存在單一實(shí)例,不管是否位于棧頂。與其他啟動(dòng)模式不同的是,這個(gè)啟動(dòng)模式可以指定棧去啟動(dòng)。例如現(xiàn)在有一個(gè)棧Main,但是你可以給活動(dòng)A指定一個(gè)棧名dev,那么啟動(dòng)A的時(shí)候就會(huì)創(chuàng)建一個(gè)棧叫做dev。所以singleTask的意思就是,當(dāng)你啟動(dòng)一個(gè)啟動(dòng)模式為singleTask的活動(dòng)的時(shí)候,如果棧中沒有相同的實(shí)例,那么就會(huì)創(chuàng)建一個(gè)新的實(shí)例放入棧中;如果指定棧中存在相同的實(shí)例,例如棧中有ABC,然后你啟動(dòng)B,那么這個(gè)時(shí)候不會(huì)去創(chuàng)建新的B實(shí)例,而是把B放到棧頂,并把A頂出去,再執(zhí)行B的onNewIntent方法,此時(shí)棧的情況就是BC。
細(xì)心的讀者會(huì)發(fā)現(xiàn)“頂出去”。是的,我們都知道棧是后進(jìn)先出的特點(diǎn),例如你往筒里放了3個(gè)羽毛球,那你想要拿到中間那個(gè)羽毛球,是不是只能先把上面那個(gè)抽出來呢,同樣的道理,要想把B提到棧頂,那么必須把A頂出來。可能會(huì)有很多讀者誤以為啟動(dòng)后是BAC,但其實(shí)是BC,因?yàn)锳得先出棧,B才能出來。同理,如果棧中是ADFBC,這個(gè)啟動(dòng)B,也是BC,上面的全部被出棧了。
singleInstance
單例模式。這個(gè)是singleTask的強(qiáng)化版本。他會(huì)自己新建一個(gè)棧并把這個(gè)新的實(shí)例放進(jìn)去,而且這個(gè)棧只能放這個(gè)活動(dòng)實(shí)例。所以當(dāng)重復(fù)啟動(dòng)這個(gè)活動(dòng)的時(shí)候,只要他存在,都是調(diào)用這個(gè)活動(dòng)onNewIntent方法并切換到這個(gè)棧中,并不會(huì)去創(chuàng)建新的實(shí)例。
設(shè)置啟動(dòng)模式的兩種方法
了解了活動(dòng)的四種啟動(dòng)模式,接下來看看如何給他指定啟動(dòng)模式。
靜態(tài)設(shè)置
靜態(tài)設(shè)置就是在AndroidManifest中給具體活動(dòng)設(shè)置啟動(dòng)模式。通過給活動(dòng)指定launchMode參數(shù)來設(shè)置啟動(dòng)模式。例如:
<activity android:name=".MainActivity"
android:launchMode="singleInstance"/>
動(dòng)態(tài)設(shè)置
動(dòng)態(tài)設(shè)置是在啟動(dòng)活動(dòng)的時(shí)候再指定啟動(dòng)模式,例如:
Intent intent = new Intent(); intent.setClass(this,SecondActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);
可以看到我們通過intent.addFlags這個(gè)方法來指定啟動(dòng)模式,這個(gè)方法傳入一個(gè)參數(shù)來指定啟動(dòng)模式,其他的參數(shù)有:
- FLAG_ACTIVITY_NEW_TASK:singleTask模式
- FLAG_ACTIVITY_SINGLE_TOP:singleTop模式
- FLAG_ACTIVITY_CLEAR_TOP:清除該活動(dòng)上方的所有活動(dòng)。一般和singleTask一起使用。但是如果你的啟動(dòng)模式是standard,那么這個(gè)活動(dòng)連他之上的所有活動(dòng)都會(huì)被出棧再創(chuàng)建一個(gè)新的實(shí)例放進(jìn)去。例如現(xiàn)在棧中是ABCD,以FLAG_ACTIVITY_CLEAR_TOP+standard模式啟動(dòng)C的時(shí)候,首先清理掉ABC,是的,C也會(huì)被清理,然后再創(chuàng)建一個(gè)新的C放進(jìn)去,執(zhí)行之后就是CD。
特別注意的坑
singleInstance返回任務(wù)棧
現(xiàn)在模擬一個(gè)場(chǎng)景:現(xiàn)在有三個(gè)活動(dòng) A,B,C。A和C的啟動(dòng)模式都是standard,B的啟動(dòng)模式是singleInstance。先啟動(dòng)A,再啟動(dòng)B,然后再啟動(dòng)C。這個(gè)時(shí)候問題來了,如果我這個(gè)時(shí)候按下返回鍵,是回到B嗎?答案是回到A。再按一下呢,返回桌面嗎?答案是回到B,再按一下再回到桌面。其實(shí)不難理解。我們都知道singleInstance會(huì)創(chuàng)建一個(gè)獨(dú)立的棧,當(dāng)我們啟動(dòng)A的時(shí)候,A位于棧First中,啟動(dòng)B的時(shí)候,就會(huì)創(chuàng)建一個(gè)棧Second并把B實(shí)例放進(jìn)去。這個(gè)時(shí)候再啟動(dòng)C,就會(huì)切換到棧FIrst,因?yàn)閟ingleInstance創(chuàng)建的棧只能放一個(gè),所以C會(huì)放到棧First中,當(dāng)按下返回的時(shí)候,棧First中的活動(dòng)就會(huì)依次出棧,直到全部出完,才會(huì)切換到棧Second中。所以要注意這個(gè)點(diǎn)。
singleTask多任務(wù)棧啟動(dòng)問題
這個(gè)問題和上面singleTop的本質(zhì)是一樣的。模擬一個(gè)場(chǎng)景:現(xiàn)在有兩個(gè)棧:First:ABC;Second:QWE。棧First位于前臺(tái),棧Second位于后臺(tái)。A位于棧頂。這個(gè)時(shí)候以singleTask的模式啟動(dòng)W,會(huì)發(fā)生什么樣的情況呢?首先會(huì)切換到棧Second,再把Q出棧,W提到棧頂,并執(zhí)行W的onNewIntent方法。這個(gè)時(shí)候按返回鍵就會(huì)把Second棧中的活動(dòng)依次出棧,全部出完后才會(huì)切換到棧First。
singleTask的TaskAffinity與allowTaskReparenting參數(shù)
前面我們講到給singleTask模式指定要啟動(dòng)的任務(wù)棧的名字,怎么指定呢?可以在AndroidManifest中指定相關(guān)的屬性,如下:
<activity android:name=".Main2Activity"
android:launchMode="singleTask"
android:taskAffinity="com.huan"
android:allowTaskReparenting="true"/>
這里解釋一下這兩個(gè)參數(shù)
- taskAffinity:指定任務(wù)棧的名字。默認(rèn)的任務(wù)棧是包名,所以不能以包名來命名。
- allowTaskReparenting:這個(gè)參數(shù)表示可不可以切換到新的任務(wù)棧,通常設(shè)置為true并和上面的參數(shù)一起使用。
我前面講到可以給singleTask的活動(dòng)指定一個(gè)棧名,然后啟動(dòng)的時(shí)候,就會(huì)切換到那個(gè)棧,并把新的活動(dòng)放進(jìn)去。但是如果設(shè)置allowTaskReparenting參數(shù)為false的話是不會(huì)切換到新的棧的。這個(gè)參數(shù)的意思是可不可以把新的活動(dòng)轉(zhuǎn)移到新的任務(wù)棧。簡(jiǎn)單點(diǎn)來說:當(dāng)我們啟動(dòng)一個(gè)singleTask活動(dòng)的時(shí)候,這個(gè)活動(dòng)還是留在啟動(dòng)他的活動(dòng)的棧中的。但是我們指定了taskAffinity這個(gè)參數(shù),或者啟動(dòng)的活動(dòng)是別的應(yīng)用中的活動(dòng),那么就會(huì)創(chuàng)建一個(gè)新的任務(wù)棧。如果allowTaskReparenting這個(gè)參數(shù)是true的話,那么這個(gè)活動(dòng)就會(huì)放到那個(gè)新的任務(wù)棧中。這樣應(yīng)該就可以明白了。所以這兩個(gè)經(jīng)常是配套一起使用的。
總結(jié)
活動(dòng)的啟動(dòng)模式有四種,每種的功能都不一樣,可以結(jié)合具體需要去使用,但是最重點(diǎn)還是要了解他的實(shí)現(xiàn)原理,棧中是怎么變化的,這個(gè)是比較重要的。了解這個(gè)之后那些特殊情況也就很容易理解了。
上面我講的只是簡(jiǎn)單的使用,關(guān)于活動(dòng)啟動(dòng)模式還有很多要了解。后續(xù)可能會(huì)解析一下,讀者也可以自行去深度了解。
參考資料
《Android開發(fā)藝術(shù)探索》 –任玉剛
以上就是淺析Activity啟動(dòng)模式的詳細(xì)內(nèi)容,更多關(guān)于Activity啟動(dòng)模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android Studio實(shí)現(xiàn)簡(jiǎn)易登錄界面制作
這篇文章主要為大家詳細(xì)介紹了Android Studio實(shí)現(xiàn)簡(jiǎn)易登錄界面制作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
android 應(yīng)用退出時(shí)不播放動(dòng)畫的解決方法
在Android應(yīng)用中,默認(rèn)情況下,當(dāng)用戶點(diǎn)擊返回按鈕退出應(yīng)用時(shí),系統(tǒng)會(huì)為應(yīng)用添加一個(gè)默認(rèn)的退出動(dòng)畫效果,本文將介紹如何在Android應(yīng)用中禁止退出動(dòng)畫的播放,感興趣的朋友一起看看吧2024-05-05
基于GridView和ActivityGroup實(shí)現(xiàn)的TAB分頁(附源碼)
今天為大家介紹下使用GridView和ActivityGroup實(shí)現(xiàn)的分頁,這里需要將Activity轉(zhuǎn)換成Window,然后再換成成View添加到容器中,具體實(shí)現(xiàn)代碼如下,感興趣的朋友可以參考下哈2013-06-06
Android中用MediaRecorder進(jìn)行錄影的實(shí)例代碼
這篇文章主要介紹了Android中用MediaRecorder進(jìn)行錄影的實(shí)例代碼,有需要的朋友可以參考一下2014-01-01
基于android中的各種顏色在drawable.xml中的值詳解
本篇文章是對(duì)在android中的各種顏色在drawable.xml中的值進(jìn)行了詳細(xì)的介紹。需要的朋友參考下2013-05-05
Android 實(shí)現(xiàn)圖片轉(zhuǎn)二進(jìn)制流及二進(jìn)制轉(zhuǎn)字符串
這篇文章主要介紹了Android 實(shí)現(xiàn)圖片轉(zhuǎn)二進(jìn)制流及二進(jìn)制轉(zhuǎn)字符串,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03
基于Android CALL && SendMes Test的相關(guān)介紹
本篇文章小編為大家介紹,Android CALL && SendMes Test 需要的朋友參考下2013-04-04

