Activity全方位了解体啰,總有你不知道的一面

關(guān)于Activity攒巍,是我們接觸Android時(shí)頻繁了解的東西嗽仪。其生命周期,啟動(dòng)模式等內(nèi)容也耳熟能詳柒莉。今天將系統(tǒng)而全面的總結(jié)Activity中的內(nèi)容闻坚。

一、Activity的生命周期

本節(jié)內(nèi)容將生命周期的情況分為兩部分介紹兢孝,第一部分先了解典型的生命周期的7個(gè)部分及Activity的狀態(tài)鲤氢。第二部分會(huì)介紹Activity在一些特殊情況下的生命周期的經(jīng)歷過程。

1.典型的生命周期的了解

先上經(jīng)典圖片西潘。



關(guān)于這張圖片卷玉,我們可能在初學(xué)Android時(shí)就有接觸,今天我們繼續(xù)回顧一下喷市。

在正常情況下相种,一個(gè)Activity從啟動(dòng)到結(jié)束會(huì)以如下順序經(jīng)歷整個(gè)生命周期:
onCreate()->onStart()->onResume()->onPause()->onStop()->onDestory()。包含了六個(gè)部分品姓,還有一個(gè)onRestart()沒有調(diào)用寝并,下面我們一一介紹這七部分內(nèi)容。

(1) onCreate():當(dāng) Activity 第一次創(chuàng)建時(shí)會(huì)被調(diào)用腹备。這是生命周期的第一個(gè)方法衬潦。在這個(gè)方法中,可以做一些初始化工作植酥,比如調(diào)用setContentView去加載界面布局資源镀岛,初始化Activity所需的數(shù)據(jù)。當(dāng)然也可借助onCreate()方法中的Bundle對象來回復(fù)異常情況下Activity結(jié)束時(shí)的狀態(tài)(后面會(huì)介紹)友驮。

(2) onRestart():表示Activity正在重新啟動(dòng)漂羊。一般情況下,當(dāng)當(dāng)前Activity從不可見重新變?yōu)榭梢姞顟B(tài)時(shí)卸留,onRestart就會(huì)被調(diào)用走越。這種情形一般是用戶行為導(dǎo)致的,比如用戶按Home鍵切換到桌面或打開了另一個(gè)新的Activity耻瑟,接著用戶又回到了這個(gè)Actvity旨指。(關(guān)于這部分生命周期的歷經(jīng)過程,后面會(huì)介紹喳整。)

(3) onStart(): 表示Activity正在被啟動(dòng)谆构,即將開始,這時(shí)Activity已經(jīng)出現(xiàn)了算柳,但是還沒有出現(xiàn)在前臺低淡,無法與用戶交互。這個(gè)時(shí)候可以理解為Activity已經(jīng)顯示出來瞬项,但是我們還看不到蔗蹋。

(4) onResume():表示Activity已經(jīng)可見了,并且出現(xiàn)在前臺并開始活動(dòng)囱淋。需要和onStart()對比猪杭,onStart的時(shí)候Activity還在后臺,onResume的時(shí)候Activity才顯示到前臺妥衣。

(5) onPause():表示 Activity正在停止皂吮,仍可見,正常情況下税手,緊接著onStop就會(huì)被調(diào)用蜂筹。在特殊情況下,如果這個(gè)時(shí)候快速地回到當(dāng)前Activity芦倒,那么onResume就會(huì)被調(diào)用(極端情況)艺挪。onPause中不能進(jìn)行耗時(shí)操作,會(huì)影響到新Activity的顯示兵扬。因?yàn)閛nPause必須執(zhí)行完麻裳,新的Activity的onResume才會(huì)執(zhí)行。

(6) onStop():表示Activity即將停止器钟,不可見津坑,位于后臺“涟裕可以做稍微重量級的回收工作疆瑰,同樣不能太耗時(shí)。

(7) onDestory():表示Activity即將銷毀昙啄,這是Activity生命周期的最后一個(gè)回調(diào)乃摹,可以做一些回收工作和最終的資源回收。

在平常的開發(fā)中跟衅,我們經(jīng)常用到的就是 onCreate()和onDestory()孵睬,做一些初始化和回收操作。

生命周期的幾種普通情況

①針對一個(gè)特定的Activity伶跷,第一次啟動(dòng)掰读,回調(diào)如下:onCreate()->onStart()->onResume()

②用戶打開新的Activiy的時(shí)候,上述Activity的回調(diào)如下:onPause()->onStop()

③再次回到原Activity時(shí)叭莫,回調(diào)如下:onRestart()->onStart()->onResume()

④按back鍵回退時(shí)蹈集,回調(diào)如下:onPause()->onStop()->onDestory()

⑤按Home鍵切換到桌面后又回到該Actitivy,回調(diào)如下:onPause()->onStop()->onRestart()->onStart()->onResume()

⑥調(diào)用finish()方法后雇初,回調(diào)如下:onDestory()(以在onCreate()方法中調(diào)用為例拢肆,不同方法中回調(diào)不同,通常都是在onCreate()方法中調(diào)用)

2.特殊情況下的生命周期

上面是普通情況下Activity生命周期的一些流程,但是在一些特殊情況下郭怪,Activity的生命周期的經(jīng)歷有些異常支示,下面就是兩種特殊情況。
①橫豎屏切換
在橫豎屏切換的過程中鄙才,會(huì)發(fā)生Activity被銷毀并重建的過程颂鸿。

在了解這種情況下的生命周期時(shí),首先應(yīng)該了解這兩個(gè)回調(diào):onSaveInstanceState和onRestoreInstanceState攒庵。

在Activity由于異常情況下終止時(shí)嘴纺,系統(tǒng)會(huì)調(diào)用onSaveInstanceState來保存當(dāng)前Activity的狀態(tài)。這個(gè)方法的調(diào)用是在onStop之前浓冒,它和onPause沒有既定的時(shí)序關(guān)系栽渴,該方法只在Activity被異常終止的情況下調(diào)用。當(dāng)異常終止的Activity被重建以后稳懒,系統(tǒng)會(huì)調(diào)用onRestoreInstanceState闲擦,并且把Activity銷毀時(shí)onSaveInstanceState方法所保存的Bundle對象參數(shù)同時(shí)傳遞給onSaveInstanceState和onCreate方法。因此僚祷,可以通過onRestoreInstanceState方法來恢復(fù)Activity的狀態(tài)佛致,該方法的調(diào)用時(shí)機(jī)是在onStart之后。其中onCreate和onRestoreInstanceState方法來恢復(fù)Activity的狀態(tài)的區(qū)別:onRestoreInstanceState回調(diào)則表明其中Bundle對象非空辙谜,不用加非空判斷俺榆。onCreate需要非空判斷。建議使用onRestoreInstanceState装哆。


橫豎屏切換的生命周期:onPause()->onSaveInstanceState()-> onStop()->onDestroy()->onCreate()->onStart()->onRestoreInstanceState->onResume()

可以通過在AndroidManifest文件的Activity中指定如下屬性:

android:configChanges = "orientation| screenSize"

來避免橫豎屏切換時(shí)罐脊,Activity的銷毀和重建,而是回調(diào)了下面的方法:

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

②資源內(nèi)存不足導(dǎo)致優(yōu)先級低的Activity被殺死
Activity優(yōu)先級的劃分和下面的Activity的三種運(yùn)行狀態(tài)是對應(yīng)的蜕琴。

(1) 前臺Activity——正在和用戶交互的Activity萍桌,優(yōu)先級最高。

(2) 可見但非前臺Activity——比如Activity中彈出了一個(gè)對話框凌简,導(dǎo)致Activity可見但是位于后臺無法和用戶交互上炎。

(3) 后臺Activity——已經(jīng)被暫停的Activity,比如執(zhí)行了onStop雏搂,優(yōu)先級最低藕施。

當(dāng)系統(tǒng)內(nèi)存不足時(shí),會(huì)按照上述優(yōu)先級從低到高去殺死目標(biāo)Activity所在的進(jìn)程凸郑。我們在平常使用手機(jī)時(shí)裳食,能經(jīng)常感受到這一現(xiàn)象。這種情況下數(shù)組存儲(chǔ)和恢復(fù)過程和上述情況一致芙沥,生命周期情況也一樣诲祸。

3.Activity的三種運(yùn)行狀態(tài)

①Resumed(活動(dòng)狀態(tài))

又叫Running狀態(tài)浊吏,這個(gè)Activity正在屏幕上顯示,并且有用戶焦點(diǎn)救氯。這個(gè)很好理解找田,就是用戶正在操作的那個(gè)界面。

②Paused(暫停狀態(tài))

這是一個(gè)比較不常見的狀態(tài)径密。這個(gè)Activity在屏幕上是可見的午阵,但是并不是在屏幕最前端的那個(gè)Activity躺孝。比如有另一個(gè)非全屏或者透明的Activity是Resumed狀態(tài)享扔,沒有完全遮蓋這個(gè)Activity。

③Stopped(停止?fàn)顟B(tài))

當(dāng)Activity完全不可見時(shí)植袍,此時(shí)Activity還在后臺運(yùn)行惧眠,仍然在內(nèi)存中保留Activity的狀態(tài),并不是完全銷毀于个。這個(gè)也很好理解氛魁,當(dāng)跳轉(zhuǎn)的另外一個(gè)界面,之前的界面還在后臺厅篓,按回退按鈕還會(huì)恢復(fù)原來的狀態(tài)秀存,大部分軟件在打開的時(shí)候,直接按Home鍵羽氮,并不會(huì)關(guān)閉它或链,此時(shí)的Activity就是Stopped狀態(tài)。

二档押、Activity的啟動(dòng)模式

1.啟動(dòng)模式的類別

Android提供了四種Activity啟動(dòng)方式:

標(biāo)準(zhǔn)模式(standard)
棧頂復(fù)用模式(singleTop)
棧內(nèi)復(fù)用模式(singleTask)
單例模式(singleInstance)

2.啟動(dòng)模式的結(jié)構(gòu)——棧

Activity的管理是采用任務(wù)棧的形式澳盐,任務(wù)棧采用“后進(jìn)先出”的棧結(jié)構(gòu)。


3.Activity的LaunchMode

(1)標(biāo)準(zhǔn)模式(standard)

每啟動(dòng)一次Activity令宿,就會(huì)創(chuàng)建一個(gè)新的Activity實(shí)例并置于棧頂叼耙。誰啟動(dòng)了這個(gè)Activity,那么這個(gè)Activity就運(yùn)行在啟動(dòng)它的那個(gè)Activity所在的棧中粒没。

例如:Activity A啟動(dòng)了Activity B筛婉,則就會(huì)在A所在的棧頂壓入一個(gè)新的Activity。


特殊情況癞松,如果在Service或Application中啟動(dòng)一個(gè)Activity爽撒,其并沒有所謂的任務(wù)棧,可以使用標(biāo)記位Flag來解決拦惋。解決辦法:為待啟動(dòng)的Activity指定FLAG_ACTIVITY_NEW_TASK標(biāo)記位匆浙,創(chuàng)建一個(gè)新棧。

應(yīng)用場景:絕大多數(shù)Activity厕妖。如果以這種方式啟動(dòng)的Activity被跨進(jìn)程調(diào)用首尼,在5.0之前新啟動(dòng)的Activity實(shí)例會(huì)放入發(fā)送Intent的Task的棧的頂部,盡管它們屬于不同的程序,這似乎有點(diǎn)費(fèi)解看起來也不是那么合理软能,所以在5.0之后迎捺,上述情景會(huì)創(chuàng)建一個(gè)新的Task,新啟動(dòng)的Activity就會(huì)放入剛創(chuàng)建的Task中查排,這樣就合理的多了凳枝。

(2)棧頂復(fù)用模式(singleTop)

如果需要新建的Activity位于任務(wù)棧棧頂,那么此Activity的實(shí)例就不會(huì)重建跋核,而是重用棧頂?shù)膶?shí)例岖瑰。并回調(diào)如下方法:

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
    }

由于不會(huì)重建一個(gè)Activity實(shí)例,則不會(huì)回調(diào)其他生命周期方法砂代。
如果棧頂不是新建的Activity,就會(huì)創(chuàng)建該Activity新的實(shí)例蹋订,并放入棧頂。


應(yīng)用場景:在通知欄點(diǎn)擊收到的通知刻伊,然后需要啟動(dòng)一個(gè)Activity露戒,這個(gè)Activity就可以用singleTop,否則每次點(diǎn)擊都會(huì)新建一個(gè)Activity捶箱。當(dāng)然實(shí)際的開發(fā)過程中智什,測試妹紙沒準(zhǔn)給你提過這樣的bug:某個(gè)場景下連續(xù)快速點(diǎn)擊,啟動(dòng)了兩個(gè)Activity丁屎。如果這個(gè)時(shí)候待啟動(dòng)的Activity使用 singleTop模式也是可以避免這個(gè)Bug的荠锭。同standard模式,如果是外部程序啟動(dòng)singleTop的Activity悦屏,在Android 5.0之前新創(chuàng)建的Activity會(huì)位于調(diào)用者的Task中节沦,5.0及以后會(huì)放入新的Task中。

(3)棧內(nèi)復(fù)用模式(singleTask)

該模式是一種單例模式础爬,即一個(gè)棧內(nèi)只有一個(gè)該Activity實(shí)例甫贯。該模式,可以通過在AndroidManifest文件的Activity中指定該Activity需要加載到那個(gè)棧中看蚜,即singleTask的Activity可以指定想要加載的目標(biāo)棧叫搁。singleTask和taskAffinity配合使用,指定開啟的Activity加入到哪個(gè)棧中供炎。

 <activity android:name=".Activity1"
             android:launchMode="singleTask"
             android:taskAffinity="com.lvr.task"
             android:label="@string/app_name">
      </activity>

關(guān)于taskAffinity的值:每個(gè)Activity都有taskAffinity屬性渴逻,這個(gè)屬性指出了它希望進(jìn)入的Task。如果一個(gè)Activity沒有顯式的指明該Activity的taskAffinity音诫,那么它的這個(gè)屬性就等于Application指明的taskAffinity惨奕,如果Application也沒有指明,那么該taskAffinity的值就等于包名竭钝。
執(zhí)行邏輯:
在這種模式下梨撞,如果Activity指定的棧不存在雹洗,則創(chuàng)建一個(gè)棧,并把創(chuàng)建的Activity壓入棧內(nèi)卧波。如果Activity指定的棧存在时肿,如果其中沒有該Activity實(shí)例,則會(huì)創(chuàng)建Activity并壓入棧頂港粱,如果其中有該Activity實(shí)例螃成,則把該Activity實(shí)例之上的Activity殺死清除出棧,重用并讓該Activity實(shí)例處在棧頂查坪,然后調(diào)用onNewIntent()方法寸宏。

對應(yīng)如下三種情況:



應(yīng)用場景:大多數(shù)App的主頁。對于大部分應(yīng)用咪惠,當(dāng)我們在主界面點(diǎn)擊回退按鈕的時(shí)候都是退出應(yīng)用击吱,那么當(dāng)我們第一次進(jìn)入主界面之后淋淀,主界面位于棧底遥昧,以后不管我們打開了多少個(gè)Activity,只要我們再次回到主界面朵纷,都應(yīng)該使用將主界面Activity上所有的Activity移除的方式來讓主界面Activity處于棧頂炭臭,而不是往棧頂新加一個(gè)主界面Activity的實(shí)例,通過這種方式能夠保證退出應(yīng)用時(shí)所有的Activity都能報(bào)銷毀袍辞。在跨應(yīng)用Intent傳遞時(shí)鞋仍,如果系統(tǒng)中不存在singleTask Activity的實(shí)例,那么將創(chuàng)建一個(gè)新的Task搅吁,然后創(chuàng)建SingleTask Activity的實(shí)例威创,將其放入新的Task中。

(4)單例模式(singleInstance)

作為棧內(nèi)復(fù)用模式(singleTask)的加強(qiáng)版,打開該Activity時(shí)谎懦,直接創(chuàng)建一個(gè)新的任務(wù)棧肚豺,并創(chuàng)建該Activity實(shí)例放入新棧中。一旦該模式的Activity實(shí)例已經(jīng)存在于某個(gè)棧中界拦,任何應(yīng)用再激活該Activity時(shí)都會(huì)重用該棧中的實(shí)例吸申。


應(yīng)用場景:呼叫來電界面。這種模式的使用情況比較罕見享甸,在Launcher中可能使用截碴。或者你確定你需要使Activity只有一個(gè)實(shí)例蛉威。建議謹(jǐn)慎使用日丹。

3.特殊情況——前臺棧和后臺棧的交互

假如目前有兩個(gè)任務(wù)棧。前臺任務(wù)棧為AB蚯嫌,后臺任務(wù)棧為CD哲虾,這里假設(shè)CD的啟動(dòng)模式均為singleTask,現(xiàn)在請求啟動(dòng)D割坠,那么這個(gè)后臺的任務(wù)棧都會(huì)被切換到前臺,這個(gè)時(shí)候整個(gè)后退列表就變成了ABCD妒牙。當(dāng)用戶按back返回時(shí)彼哼,列表中的activity會(huì)一一出棧,如下圖湘今。


如果不是請求啟動(dòng)D而是啟動(dòng)C敢朱,那么情況又不一樣,如下圖摩瞎。

調(diào)用SingleTask模式的后臺任務(wù)棧中的Activity拴签,會(huì)把整個(gè)棧的Actvity壓入當(dāng)前棧的棧頂。singleTask會(huì)具有clearTop特性旗们,把之上的棧內(nèi)Activity清除蚓哩。

4.Activity的Flags

Activity的Flags很多,這里介紹集中常用的上渴,用于設(shè)定Activity的啟動(dòng)模式岸梨。可以在啟動(dòng)Activity時(shí)稠氮,通過Intent的addFlags()方法設(shè)置曹阔。

**(1)FLAG_ACTIVITY_NEW_TASK **
其效果與指定Activity為singleTask模式一致。

(2)FLAG_ACTIVITY_SINGLE_TOP
其效果與指定Activity為singleTop模式一致隔披。

(3)FLAG_ACTIVITY_CLEAR_TOP
具有此標(biāo)記位的Activity赃份,當(dāng)它啟動(dòng)時(shí),在同一個(gè)任務(wù)棧中所有位于它上面的Activity都要出棧奢米。如果和singleTask模式一起出現(xiàn)抓韩,若被啟動(dòng)的Activity已經(jīng)存在棧中,則清除其之上的Activity鬓长,并調(diào)用該Activity的onNewIntent方法谒拴。如果被啟動(dòng)的Activity采用standard模式,那么該Activity連同之上的所有Activity出棧痢士,然后創(chuàng)建新的Activity實(shí)例并壓入棧中彪薛。

以上就是本篇文章的內(nèi)容。本篇文章的棧操作的圖片來自于xybCoder怠蹂,特別感謝善延!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市城侧,隨后出現(xiàn)的幾起案子易遣,更是在濱河造成了極大的恐慌,老刑警劉巖嫌佑,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豆茫,死亡現(xiàn)場離奇詭異侨歉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)揩魂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進(jìn)店門幽邓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人火脉,你說我怎么就攤上這事牵舵。” “怎么了倦挂?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵畸颅,是天一觀的道長。 經(jīng)常有香客問我方援,道長没炒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任犯戏,我火速辦了婚禮送火,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘笛丙。我一直安慰自己漾脂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布胚鸯。 她就那樣靜靜地躺著,像睡著了一般笨鸡。 火紅的嫁衣襯著肌膚如雪姜钳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天形耗,我揣著相機(jī)與錄音哥桥,去河邊找鬼。 笑死激涤,一個(gè)胖子當(dāng)著我的面吹牛拟糕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播倦踢,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼送滞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辱挥?” 一聲冷哼從身側(cè)響起犁嗅,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晤碘,沒想到半個(gè)月后褂微,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體功蜓,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年宠蚂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了式撼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,865評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡求厕,死狀恐怖端衰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情甘改,我是刑警寧澤旅东,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站十艾,受9級特大地震影響抵代,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜忘嫉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一荤牍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧庆冕,春花似錦康吵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拷姿,卻和暖如春卜朗,著一層夾襖步出監(jiān)牢的瞬間蟀伸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留得封,地道東北人甸陌。 一個(gè)月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓湘捎,卻偏偏與公主長得像钟沛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子伏穆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評論 2 361

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