關(guān)于Activity的啟動(dòng)模式

Activity的啟動(dòng)模式

Activity作為安卓四大組件之首,它的確非常重要,上篇文章我們介紹了Activity的生命周期,其實(shí)Activity的啟動(dòng)模式也是一個(gè)難點(diǎn),有時(shí)為了項(xiàng)目的特殊需求,我們需要使用到Activity的啟動(dòng)模式,下面我們就具體的介紹Activity的啟動(dòng)模式和標(biāo)志位。

1.1Activity的LaunchMode(啟動(dòng)模式)

首先我們開介紹一下Activity為什么需要啟動(dòng)模式。在默認(rèn)情況下,多次啟動(dòng)同一個(gè)Activity,系統(tǒng)會(huì)創(chuàng)建多個(gè)實(shí)例,并把這些實(shí)例一一的壓入任務(wù)棧中。當(dāng)我們單擊返回鍵的時(shí)候,就會(huì)一一回退。我們知道在數(shù)據(jù)結(jié)構(gòu)中,棧是先進(jìn)后出的。其實(shí)就是每按一次返回鍵,銷毀一個(gè)Activity,就會(huì)有一個(gè)Activity實(shí)例出棧,直到棧內(nèi)為空的時(shí)候,系統(tǒng)將任務(wù)?;厥?。這就是Activity在默認(rèn)情況下的啟動(dòng)方式。在這里我們會(huì)不會(huì)發(fā)現(xiàn)一個(gè)問題:多次啟動(dòng)同一個(gè)Activity系統(tǒng)竟然多次創(chuàng)建實(shí)例,這是不是感覺很奇葩?在學(xué)習(xí)設(shè)計(jì)模式的時(shí)候,我們都知道有單實(shí)例模式,我想Android系統(tǒng)也不會(huì)那么笨。是的,Android系統(tǒng)其實(shí)早就知道這一點(diǎn)了,所以Android系統(tǒng)在設(shè)計(jì)的時(shí)候提供了啟動(dòng)模式來修改這種默認(rèn)的啟動(dòng)行為。目前有四種啟動(dòng)模式:standard、singleTop、singleTask、singleInstance。下面就對這四種啟動(dòng)模式進(jìn)行一一的介紹:

(1)standard

standard:標(biāo)準(zhǔn)模式,這是系統(tǒng)默認(rèn)的啟動(dòng)模式。每次啟動(dòng)一個(gè)Activity就會(huì)創(chuàng)建一個(gè)Activity的實(shí)例。不管這個(gè)實(shí)例是否存在都會(huì)進(jìn)行創(chuàng)建。每次創(chuàng)建Activity的生命周期,也都是符合正常情況下Activity的生命周期。創(chuàng)建一個(gè)Activity實(shí)例,就會(huì)把這個(gè)實(shí)例壓入任務(wù)棧中,一個(gè)任務(wù)??梢杂卸鄠€(gè)Activity實(shí)例,同一個(gè)Activity的各個(gè)實(shí)例也可以對應(yīng)不同的任務(wù)棧。在標(biāo)準(zhǔn)模式下:一個(gè)Activity由誰啟動(dòng)的,實(shí)例就會(huì)壓入啟動(dòng)者所在的任務(wù)棧,簡單的說就是:假如一個(gè)Activity A 啟動(dòng)了 Activity B 那么B的實(shí)例就會(huì)壓入A所在的任務(wù)棧中。在這我們提一點(diǎn),不知道讀者是否遇到這樣一個(gè)問題。使用ApplicationContext去啟動(dòng)一個(gè)Activity會(huì)報(bào)如下錯(cuò)誤:

接下來筆者將介紹如何重現(xiàn)這樣的錯(cuò)誤信息:

通過上面知道我們?nèi)绻肁ctivity A ?通過標(biāo)準(zhǔn)模式去啟動(dòng)Activity B ?B的實(shí)例會(huì)壓入A的實(shí)例所在的任務(wù)棧中。這個(gè)很容易理解。這里介紹的都是通過Activity去啟動(dòng)另一個(gè)Activity是沒問題的,因?yàn)锳ctivity啟動(dòng)者會(huì)有對應(yīng)的任務(wù)棧。假如我們通過廣播接受者去啟動(dòng)一個(gè)Activity呢?如下圖所示:

通過標(biāo)準(zhǔn)模式,以上的代碼能啟動(dòng)一個(gè)Activity嗎,還是會(huì)報(bào)上面所說的錯(cuò)誤?筆者告訴大家,答案是:

《1》當(dāng)這個(gè)廣播接收者是通過手動(dòng)在Activity ?A 中注冊的情況下是可以的,上面代碼中的Context屬于Activity A 對象,這個(gè)時(shí)候通過啟動(dòng) Activity B其實(shí)就是通過這個(gè)Activity A 啟動(dòng)的,B的實(shí)例就會(huì)壓入到Activity B 實(shí)例所在的任務(wù)棧。這樣不會(huì)報(bào)錯(cuò),正常啟動(dòng)。

《2》當(dāng)這個(gè)廣播接收者是通過在Manifest中注冊的情況下是不可的,就會(huì)報(bào)上面所說的錯(cuò)誤信息。這個(gè)時(shí)候上面代碼

中的Context是屬于ReceiverRestrictedContext@41a7c2b8廣播接受者的,廣播接受者沒有對應(yīng)的任務(wù)棧,因此不能通過context去啟動(dòng)一個(gè)Activity。當(dāng)然假如一定要啟動(dòng)Activity也是可以的,我們可以進(jìn)行設(shè)置標(biāo)志位:FLAG_ACTIVITY_NEW_TASK。其實(shí)就是啟動(dòng)一個(gè)新的任務(wù)棧,把啟動(dòng)的Activity壓入這個(gè)新的任務(wù)棧中。其實(shí)這種啟動(dòng)模式,就是下面會(huì)介紹的另一種啟動(dòng)模式:sinleTask啟動(dòng)模式

(2)singleTop

singleTop:棧頂復(fù)用模式。同樣用例子說明:當(dāng)前任務(wù)棧里的情況是A B C D ,A位于棧頂,C位于棧底。

《1》通過singleTop模式Activity D啟動(dòng)Activity A,這個(gè)時(shí)候不會(huì)創(chuàng)建A的實(shí)例,只是繼續(xù)使用棧頂中的A,調(diào)用了onNewInstane方法,通過此方法的參數(shù),我們可以取出當(dāng)前請求的數(shù)據(jù)。既然不會(huì)重新創(chuàng)建A,所以A的生命周期方法:onCreate、onStart、onResume方法不會(huì)被調(diào)用。這個(gè)時(shí)候棧內(nèi)的情況是:A B C D。

《2》同樣通過singleTop模式Activity D啟動(dòng)Activity B ,由于B不在棧頂,這個(gè)時(shí)候會(huì)創(chuàng)建B的實(shí)例,開始B的生命周期方法。棧內(nèi)情況:B A B C D,這個(gè)應(yīng)該很容易理解,筆者在這就不多說了。

(3)singleTask

singleTask:棧內(nèi)復(fù)用模式。通過棧頂復(fù)用模式的學(xué)習(xí),我想學(xué)習(xí)棧內(nèi)復(fù)用模式應(yīng)該會(huì)比較容易的理解。這是一種單實(shí)例模式,在這種情況下,如果通過singleTask模式去啟動(dòng)一個(gè)Activity A,首先系統(tǒng)會(huì)尋找是否存在A所需要的任務(wù)棧,如果不存在,則創(chuàng)建任務(wù)棧,再創(chuàng)建A的實(shí)例壓入任務(wù)棧中。如果存在,則檢查棧中是否存在A的實(shí)例,如果不存在,創(chuàng)建A的實(shí)例壓入棧中。如果存在,則把A移動(dòng)到棧頂,假如之前棧內(nèi)之前的情況是 D C B A ,D位于棧頂,這個(gè)時(shí)候把A移到棧頂,由于singleTask具有clearTop效果,會(huì)導(dǎo)致A 上面的全部出棧,所以把A移到棧頂之后棧內(nèi)的情況是A。下面用例子來說明:

《1》棧S1 的情況是 A B C, A位于棧頂。創(chuàng)建D,并且所需的任務(wù)棧是S2。這個(gè)時(shí)候棧S2和實(shí)例均不存在,則需要?jiǎng)?chuàng)建任務(wù)棧S2和D實(shí)例,把D實(shí)例壓入S2中。

《2》假如創(chuàng)建D所需的棧是S1,這個(gè)時(shí)候,直接創(chuàng)建D實(shí)例,壓入S1中。S1的情況是:D A B C

《3》假如S1的情況是 A B C D ,創(chuàng)建D所需的任務(wù)棧是S1,這個(gè)時(shí)候S1已經(jīng)存在,D也存在。所以直接把D移到棧頂,最后由于clearTop模式,S1的情況是A

(4)singleInstance

singleInstance:單實(shí)例模式,這種模式具有singleTask模式所有的特性。和singleTask不同的是,通過singleInstance模式啟動(dòng)的Activity所在的任務(wù)棧只能有一個(gè)實(shí)例。而通過singleTask啟動(dòng)的Activity所在任務(wù)??梢杂胁煌膶?shí)例,只是同一個(gè)Activity只能有一個(gè)實(shí)例。

Activity的Flag(標(biāo)志位)

在上面介紹Activity的啟動(dòng)模式的時(shí)候,我們曾經(jīng)提到,假如通過ApplicationContext去啟動(dòng)一個(gè)Activity是不行的。會(huì)報(bào):

AndroidRuntimeException: Calling startActivity() from outside of an Activity,Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

錯(cuò)誤的信息就是需要一個(gè)標(biāo)志位的意思。

下面我們就介紹一下標(biāo)志位:標(biāo)志位有很多,這里主要分析一下比較常用的標(biāo)志位。有的標(biāo)志位可以設(shè)置Activity的啟動(dòng)模式。有的標(biāo)志位可以影響Activity 的運(yùn)行狀態(tài)。大部分情況下我們不需要去指定標(biāo)志位,對標(biāo)志位理解即可。

(1)FLAG_ACTIVITY_NEW_TASK

該標(biāo)志位的作用是設(shè)置Activity的啟動(dòng)模式是singleTask 即棧內(nèi)復(fù)用模式。

(2)FLAG_ACTIVITY_SINGLE_TOP

該標(biāo)志位的作用是設(shè)置Activity的啟動(dòng)模式是singleTop模式 即單實(shí)例模式

(3)FLAG_ACTIVITY_CLEAR_TOP

該標(biāo)志位的作用是啟動(dòng)一個(gè)Activity,該Activty實(shí)例所在的任務(wù)棧中所有在該實(shí)例之上的實(shí)例都要出棧。本身singleTop啟動(dòng)模式就具有該clearTop特性

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容