上篇講述了Activity的生命周期,這篇我們來聊聊啟動(dòng)模式(LaunchMode),下面開始正文
Activity任務(wù)棧(Task)
在說啟動(dòng)模式之前,我們先了解下Activity的任務(wù)棧,什么是任務(wù)棧?舉個(gè)例子,今天我們需要做一個(gè)搜索功能,那么這個(gè)搜索功能就是一個(gè)任務(wù),開發(fā)這個(gè)功能需要用到Activity,那么,當(dāng)我們啟動(dòng)這個(gè)Activity時(shí),系統(tǒng)會(huì)給我們創(chuàng)建一個(gè)容器,去存儲(chǔ)我們所需的Activity,這個(gè)容器就是Activity的任務(wù)棧,主要是存儲(chǔ)我們的Activity,在默認(rèn)情況下,每個(gè)應(yīng)用都有一個(gè)Task,每當(dāng)創(chuàng)建一個(gè)新Activity,就會(huì)加載到Task之中,每個(gè)Activity都可以跨進(jìn)程進(jìn)行通信,最簡單的例子就是,點(diǎn)擊打電話按鈕,喚起系統(tǒng)的打電話界面,Task遵循的是先進(jìn)后出順序,也就是說,最新創(chuàng)建出來的Activity會(huì)處于棧頂
后臺(tái)任務(wù)棧(Back Stack)
什么是后臺(tái)任務(wù)棧?當(dāng)ActivityA打開了ActivityB,打開之后,ActivityA就會(huì)被存放到Back Stack之中,當(dāng)點(diǎn)擊back鍵返回到ActivityA的時(shí)候,系統(tǒng)先把ActivityB銷毀,然后從Back Stack中把ActivityA拿出,Back Stack遵循的順序是后進(jìn)先出,也可以說是先進(jìn)后出,例如上面的例子,用戶在啟動(dòng)了打電話界面后,我們應(yīng)用的Activity就會(huì)存放到Back Stack之中,當(dāng)用戶點(diǎn)擊了back鍵返回我們應(yīng)用時(shí),系統(tǒng)就會(huì)從Back Stack中將Activity拿出來顯示給用戶,如果用戶繼續(xù)點(diǎn)擊back鍵,則一層一層的將Activity拿出來顯示,如果Back Stack中沒有了Activity,那應(yīng)用就退出了,這里要注意一點(diǎn)是,如果ActivityA打開ActivityB之后就finish了,那么ActivityA是不會(huì)被添加到Back Stack中,如果有多個(gè)Task的話,用戶點(diǎn)擊back回退時(shí),系統(tǒng)會(huì)先從當(dāng)前Activity所處在的Task中回退,直到?jīng)]有了Activity,再去尋找下一個(gè)Task回退,以此循環(huán),至于怎么知道Task的排序,其實(shí)創(chuàng)建Task的時(shí)候,系統(tǒng)就會(huì)幫我們記錄好了
這里就不進(jìn)行深入的探討了,有興趣的自己去研究下
LaunchMode
Activity的啟動(dòng)模式有4種:standard,singleTop,singleTask,singleInstance,現(xiàn)在就來說說他們的差別
1,standard:Activity默認(rèn)的啟動(dòng)模式,在這種啟動(dòng)模式下,每一個(gè)Activity創(chuàng)建之后,都會(huì)加載到Task之中,也是大多數(shù)場景用到的,但這有個(gè)弊端就是Task中的Activity越來越多,即使是同名的Activity,也會(huì)被創(chuàng)建,舉個(gè)例子,在ActivityA中添加個(gè)button,點(diǎn)擊之后啟動(dòng)自己,這時(shí),系統(tǒng)會(huì)繼續(xù)幫我們創(chuàng)建ActivityA,任務(wù)棧中就會(huì)繼續(xù)添加ActivityA
2,singleTop:這種模式就是說取出棧頂?shù)腁ctivity,假設(shè)有A,B,C,D四個(gè)Activity,ActivityD處于棧頂,這時(shí)候ActivityD啟動(dòng)它自己,系統(tǒng)就不會(huì)創(chuàng)建一個(gè)ActivityD,而是回調(diào)ActivityD的onNewIntent方法,假如ActivityD不處于棧頂,系統(tǒng)則會(huì)創(chuàng)建出來,所以,總結(jié)就是,當(dāng)Activity處于棧頂并且啟動(dòng)自己的時(shí)候,才不會(huì)被創(chuàng)建,否則都會(huì)被創(chuàng)建出來
舉個(gè)例子:假如有個(gè)SearchActivity,有個(gè)輸入框,輸入商品名字后搜素需要跳轉(zhuǎn)到另一個(gè)SearchResultActivty,而SearchResultActivty中也有搜索功能,假如是standard模式,我連續(xù)搜索10條,那么系統(tǒng)就會(huì)創(chuàng)建10個(gè)一模一樣的Activity,用戶得需要點(diǎn)擊10次back才可以返回到最初的Activity,這顯然是不合理的,而如果是singleTop模式,這樣我搜索出來結(jié)果之后,啟動(dòng)自己,然后回調(diào)onNewIntent方法,獲取到數(shù)據(jù)之后刷新,是不是就合理多了呢?
3,singleTask:指的是當(dāng)前Activity是唯一的,不允許有多個(gè)存在,如果已經(jīng)存在了,再次啟動(dòng)它的時(shí)候,它就會(huì)調(diào)用onNewIntent方法,如果不存在,系統(tǒng)就會(huì)幫我們創(chuàng)建出來,這個(gè)模式比較復(fù)雜,下面單獨(dú)拿出來說
4,singleInstance:跟singleTask有點(diǎn)類似,但差別就是,任務(wù)棧中只允許有目標(biāo)Activity,也就是說,如果是這種模式啟動(dòng)的Activity,系統(tǒng)會(huì)單獨(dú)分配一個(gè)Task給Activity,而Task中只有這個(gè)Activity,如果多個(gè)Activity是以這種模式啟動(dòng)的,那就會(huì)存在多個(gè)Task
singleTask
我們先來看一個(gè)例子,首先創(chuàng)建兩個(gè)Activity,MainActivity和SecondActivity,SecondActivity指定啟動(dòng)模式是singleTask,然后MainActivity啟動(dòng)SecondActivity,SecondActivity中可以啟動(dòng)MainActivity和它自己,我們來看看變化
1,首先MainActivity創(chuàng)建的時(shí)候,打印下TaskId,然后我們啟動(dòng)SecondActivity
2,SecondActivity第一次創(chuàng)建時(shí),打印出的Task的Id,我們發(fā)現(xiàn)兩個(gè)Id是一樣的,因?yàn)樗麄兲幵谕粋€(gè)任務(wù)棧中,然后SecondActivity啟動(dòng)MainActivity
3,Id還是一樣,但注意了,因?yàn)镸ainActivity是默認(rèn)模式啟動(dòng)的,所以這里的MainActivity被創(chuàng)建了兩次實(shí)例,然后我們繼續(xù)啟動(dòng)SecondActivity
4,神奇的地方來了,之前說了SecondActivity如果存在,就不會(huì)重新創(chuàng)建,但是,為什么MainActivity會(huì)被銷毀了呢?那是因?yàn)椋付藄ingleTask模式的Activity被啟動(dòng)的時(shí)候,它會(huì)先檢查是不是處于棧頂,如果不是,它會(huì)將在它之上的Activity全部銷毀掉,在第2步的時(shí)候我們啟動(dòng)了MainActivity,這時(shí)候MainActvity處于SecondActivity之上,再去啟動(dòng)SecondActivity時(shí)候,它就會(huì)將MainActivity銷毀
5,然后SecondActivity啟動(dòng)自己的時(shí)候,就跟之前一樣了,實(shí)例存在了就調(diào)用onNewIntent方法
taskAffinity
這個(gè)屬性是指Activity希望進(jìn)入的是哪個(gè)Task,每個(gè)Activity都有taskAffinity屬性,這個(gè)屬性指出了它希望進(jìn)入的Task。如果一個(gè)Activity沒有指明該 Activity的taskAffinity,那么它的這個(gè)屬性就等于Application指明的taskAffinity,如果 Application也沒有指明,那么該taskAffinity的值就等于包名。而Task也有自己的affinity屬性,它的值等于它的根 Activity的taskAffinity的值
singleTask建議和taskAffinity一起使用,這樣才會(huì)發(fā)揮它最好的效果,那么,他們是怎么工作的呢?
1、如果存在,那么檢查是否實(shí)例化,如果已經(jīng)實(shí)例化,那么銷毀在該Activity以上的Activity并調(diào)用onNewIntent。如果沒有實(shí)例化,那么該Activity實(shí)例化并入棧。
2、如果不存在,那么就重新創(chuàng)建Task,并入棧。
這里不做深入的描述了,有興趣的可以去看看這個(gè)屬性,現(xiàn)在來說說該注意的地方:
1,具有相同的affinity的activity(即設(shè)置了相同taskAffinity屬性的activity)屬于同一個(gè)任務(wù)。
2,默認(rèn)情況下,一個(gè)應(yīng)用中的所有activity具有相同的taskAffinity,即應(yīng)用程序的包名。我們可以通過設(shè)置不同的taskAffinity屬性給應(yīng)用中的activity分組,也可以把不同的應(yīng)用中的activity的taskAffinity設(shè)置成相同的值。
3, 為一個(gè)activity的taskAffinity設(shè)置一個(gè)空字符串,表明這個(gè)activity不屬于任何task。
4,如果不設(shè)置這個(gè)屬性,則Activity都會(huì)同處在同個(gè)Task中,如果設(shè)置了,則會(huì)為Activity開啟一個(gè)新的Task,然后將同個(gè)taskAffinity屬性的Activity列入
為什么說最好singleTask建議和taskAffinity一起使用呢?當(dāng)我們指定了taskAffinity之后,用戶點(diǎn)擊back回退的時(shí)候,會(huì)遵循Back Stack的回退原則,因?yàn)橹付╰askAffinity的Activity是單獨(dú)在一個(gè)Task里面,所以回退的時(shí)候不會(huì)回退到我們之前的Activity,就不會(huì)影響我們之前Activity的邏輯了
最后來看看指定了taskAffinity和沒指定taskAffinity的Task的差別,方法很簡單,在AndroidMainfest.xml里指定就可以了
不難看出,默認(rèn)情況下是同處在一個(gè)Task中,而指定的,則會(huì)單獨(dú)分配出一個(gè)Task
好了,這篇文章到這就結(jié)束了,如果什么建議歡迎提出來,反正我也不會(huì)改,哼~