一移斩、為什么需要啟動模式
默認(rèn)情況下谷异,當(dāng)我們多次啟動同一個activity的時候庸疾,系統(tǒng)會創(chuàng)建多個實例并把它們一一放入任務(wù)棧中,當(dāng)點擊back按鍵的時候两嘴,把棧中的activity一一回退段直。任務(wù)棧是“后進(jìn)先出”的結(jié)構(gòu)。這樣會照成同一個activity重復(fù)創(chuàng)建多個實例溶诞,因此activity設(shè)計了四種啟動模式來修改系統(tǒng)的默認(rèn)行為。
二决侈、Activity的四種啟動方式
1螺垢、standard:標(biāo)準(zhǔn)模式
系統(tǒng)默認(rèn)的啟動方式,每次啟動一個activity都會重新創(chuàng)建一個新的實例赖歌,不管這個實例是否已經(jīng)存在枉圃。被重新創(chuàng)建的activity都會調(diào)用onCreate、onStart庐冯、onResume方法孽亲。這個模式下,一個任務(wù)棧中可以有多個實例展父。這種模式下返劲,誰啟動這個activity,那么這個activity就運行在啟動它的任務(wù)棧中栖茉。比如A activity啟動B activity(standard模式)篮绿,那么B activity就運行在A activity的任務(wù)棧中。
由此可見如果用非activity的content去啟動standard模式的activity就會報錯吕漂,如Application的cantent去調(diào)用startActivity()方法亲配,就會報錯,是因為application沒有自己的任務(wù)棧。
2吼虎、singleTop:棧頂復(fù)用模式
在這種模式下犬钢,如果新activity已經(jīng)位于任務(wù)棧的棧頂,那么此activity不會被重復(fù)創(chuàng)建思灰,同時它的onNewIntent方法會被回調(diào)玷犹,同個此方法的參數(shù)我們可以取出當(dāng)前請求的信息。這時這個activity的onCreate官辈、onStart和onResume方法不會被系統(tǒng)調(diào)用箱舞。如果新activity的實例已經(jīng)存在但是不位于棧頂,那么新的activity任然會被重新創(chuàng)建拳亿,系統(tǒng)會調(diào)用onCreate晴股、onStart和onResume方法。
舉個例子:棧內(nèi)存在ABCD四個activity肺魁,A位于棧底电湘,D位于棧頂
再次啟動D,D的啟動模式為singleTop鹅经,棧內(nèi)的情況仍為ABCD
再次啟動B寂呛,B的啟動模式為singleTop,棧內(nèi)的情況為ABCDB
再次啟動D瘾晃,D的啟動模式為standard贷痪,棧內(nèi)的情況為ABCDBD
給activity設(shè)置啟動模式
1、在AndroidMenifest.xml中設(shè)置啟動方式
<activity android:name=".MainActivity"
android:launchMode="singleTop"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
2蹦误、在intent中設(shè)置標(biāo)志位為activity設(shè)置啟動模式
var intent = Intent(this,SecondActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
3劫拢、singleTask:棧內(nèi)復(fù)用模式
這是一種單實例模式,在這種模式下强胰,只要Activity在一個棧內(nèi)存在舱沧,那么多次啟動此activity都不會重新創(chuàng)建實例,和singleTop一樣偶洋,系統(tǒng)會調(diào)用onNewIntent熟吏。具體一點就是當(dāng)1activity(singleTask模式)被啟動時,系統(tǒng)會在尋找是否存在A activity所需要的任務(wù)棧玄窝,如果不存在會創(chuàng)建一個A activity 需要的任務(wù)棧牵寺,并把A activity壓入任務(wù)棧,如果存在A activity需要的任務(wù)棧恩脂,那么就會查找任務(wù)棧中是否有A activity的實例缸剪,如果存在,就會A activity調(diào)到棧頂东亦,調(diào)用onNewIntent方法杏节,并把A activity上面的activity清出棧唬渗。如果不存在創(chuàng)建A activity的實例,并壓入棧奋渔。
舉個例子D activity需要啟動,D activity的啟動模式是singleTask模式镊逝,需要任務(wù)棧T1
任務(wù)棧T1中有ABC三個activity明垢,這時啟動D寺晌,D會被壓入T1中善玫,T1中有ABCD四個activity
任務(wù)棧T1再次啟動A(singleTask模式)太防,調(diào)用A的onNewIntent方法,這時BCD會彈出棧碉咆,棧中只有A一個activity
任務(wù)棧T2中有ABC三個activity扮叨,這時啟動D沉桌,系統(tǒng)會先創(chuàng)建任務(wù)棧T1藤树,并把D壓入T1中
4浴滴、singleInstance:單實例模式
這是一種加強的singleTask模式,它除了具有singleTask的所有特性外岁钓,還加強了一點升略,那就是具有此種模式下的activity只能單獨位于一個任務(wù)棧中。這個任務(wù)棧中只有一個activity屡限,由于棧內(nèi)復(fù)用的特性品嚣,后續(xù)的請求都不會創(chuàng)建新的activity,除非這個獨特的任務(wù)棧被系統(tǒng)銷毀钧大。
三翰撑、舉個特殊情況的例子
現(xiàn)在有兩個任務(wù)棧,一個前臺任務(wù)棧中有AB兩個activity啊央,另一個后臺任務(wù)棧有CD兩個activity眶诈,并且CD兩個activity的啟動方式都為singleTask。
情景1劣挫、在B中啟動D,那么整個后退列表就變成了ABCD,用戶點擊back按鈕东帅,D彈出压固,再次點擊back,C彈出靠闭,再次點擊back帐我,B彈出。
情景2愧膀、在B中啟動C拦键,那么整個后退列表就變成ABC,用戶點擊back按鈕,C彈出檩淋,再次點擊back芬为,B彈出
四萄金、TaskAffinity
TaskAffinity可以翻譯成任務(wù)相關(guān)性,這個參數(shù)標(biāo)識了一個activity所需要的的任務(wù)棧的名稱媚朦,默認(rèn)情況下所有activity的任務(wù)棧的名稱為應(yīng)用的包名氧敢。當(dāng)然,我們可以為每個activity單獨指定一個TaskAffinity屬性询张,這個屬性必須不能和包名相同孙乖,否則就沒有意義了。
TaskAffinity的設(shè)置在AndroidMenifest.xml中
<activity android:name=".SecondActivity"
android:taskAffinity="com.study.task.one">
</activity>
查看任務(wù)棧的方法
adb shell dumpsys activity
//日志很多直接查詢Running activities(most recent first)這一塊
TaskAffinity屬性主要和singleTask啟動模式或者allowTaskReparenting屬性配合使用份氧。
另外任務(wù)棧分為前臺任務(wù)棧和后臺任務(wù)棧唯袄,后臺任務(wù)棧中的activity處于暫停狀態(tài),用戶可以通過切換將后臺任務(wù)棧掉到前臺蜗帜。
1恋拷、當(dāng)TaskAffinity和singleTask配合使用的時候,具有該模式的activity會運行在名稱和TaskAffinity相同的任務(wù)棧中钮糖。
2梅掠、android:allowTaskReparenting的主要作用是activity的遷移,即從一個task遷移到另一個task店归,這個遷移跟activity的taskAffinity有關(guān)阎抒,必須是從一個跟該activity taskAffinity不同的task中遷移到跟它taskAffinity相同的task中。
舉個例子:
①AB兩個activity消痛,啟動模式為standard且叁,任務(wù)棧為com.yusong.study(包名),CD兩個activity秩伞,啟動模式為singleTask逞带,且TaskAffinity為com.yusong.task,啟動順序為A中啟動B,B中啟動C纱新,C中啟動D
<activity android:name=".DActivity" android:launchMode="singleTask" android:taskAffinity="com.yusong.task"/>
<activity android:name=".CActivity" android:launchMode="singleTask" android:taskAffinity="com.yusong.task"/>
<activity android:name=".BActivity" />
<activity android:name=".AActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
啟動應(yīng)用展氓,通過adb shell dumpsys activity,查看任務(wù)棧
通過日志我們能看到有兩個任務(wù)棧脸爱,分別為com.yusong.study和com.yusong.task遇汞,并且每個任務(wù)棧有兩個activity