上一篇說了些正常情況下的Activity的生命周期,這篇說一說異常情況下的Activity的生命周期,這里異常情況是指,資源相關(guān)的配置發(fā)生改變、系統(tǒng)內(nèi)存不足Activity被殺死。
1.資源相關(guān)的配置發(fā)生改變
最典型的情況就是屏幕發(fā)生旋轉(zhuǎn),當(dāng)一個(gè)Activity啟動(dòng)后,這是時(shí)屏幕旋轉(zhuǎn)后,它的生命周期是這樣的:onPause->onStop->onDestroy->onCreate->onStart->onResume
可以看出,當(dāng)前Activity相當(dāng)于被重新啟動(dòng)了一樣,你在此Activity做的一切操作都會(huì)被銷毀,例如在EditText中輸入的文字,RecyclerView的滾動(dòng)位置等。但是Activity是在異常情況下被終止的,系統(tǒng)會(huì)調(diào)用onSaveInstanceState保存當(dāng)前Activity的狀態(tài),當(dāng)Activity被重新創(chuàng)建后系統(tǒng)會(huì)調(diào)用onRestoreInstanceState,并且把Activity銷毀時(shí)onSaveInstanceState方法所保存的Bundle對(duì)象作為參數(shù)同時(shí)傳遞給onRestoreInstanceState和onCreate方法。因此,我們可以通過onRestoreInstanceState和onCreate方法來判斷Activity是否被重建了,如果被重建了,那么我們就可以取出之前保存的數(shù)據(jù)并恢復(fù)。我們經(jīng)常在onCreate中看到的一個(gè)Bundle 類型的savedInstanceState就是做這個(gè)用。

而onSaveInstanceState、onRestoreInstanceState同樣也有這個(gè)參數(shù)。

所以當(dāng)一個(gè)Activity啟動(dòng)后,這是時(shí)屏幕旋轉(zhuǎn)后,它的生命周期其實(shí)是這樣的:onPause->onSaveInstanceState->onStop->onDestroy->onCreate->onStart->onRestoreInstanceState->onResume。這里需要注意的是,onSaveInstanceState的調(diào)用時(shí)機(jī)一定在onStop之前但是不一定在onPause之后,一般是在onPause之后,但是也有可能會(huì)在onPause之前調(diào)用。onRestoreInstanceState則是onStart之后。
這里我們注意到一點(diǎn)onCreate和onRestoreInstanceState都可以進(jìn)行數(shù)據(jù)恢復(fù),那么我們?cè)撚媚膫€(gè)做數(shù)據(jù)恢復(fù)呢?官方給出的建議是使用onRestoreInstanceState進(jìn)行數(shù)據(jù)恢復(fù),原因很簡(jiǎn)單,如果我們用onCreate中Bundle類型的savedInstanceState參數(shù)在正常調(diào)用時(shí)是空的,我們需要做額外的非空判斷,但是onRestoreInstanceState中Bundle類型的savedInstanceState參數(shù)只要onRestoreInstanceState被調(diào)用則一定不為空,即便你沒有在onSaveInstanceState做保存操作。
比如我們直接在onRestoreInstanceState中把Bundle類型的savedInstanceState參數(shù)給打印出來

控制臺(tái)輸出是這樣的

雖然可能看不懂這是啥,但是至少不是null,同樣如果在onCreate直接打印參數(shù)savedInstanceState,則正常啟動(dòng)時(shí)會(huì)直接報(bào)錯(cuò)。
2.系統(tǒng)內(nèi)存不足Activity被殺死
這種情況我們不好模擬,但是其數(shù)據(jù)存儲(chǔ)和恢復(fù)過程和情況1完全一致。這里我們描述一下Activity的優(yōu)先級(jí)情況。Activity按照優(yōu)先級(jí)從高到低,可以分為如下三種:
(1).前臺(tái)Activity——正在和用戶交互的Activity,優(yōu)先級(jí)最高。
(2).可見但非前臺(tái)Activity——比如Activity中彈出了一個(gè)對(duì)話框,導(dǎo)致Activity可見但是位于后臺(tái)無法和用戶直接交互。
(3).后臺(tái)Activity——已經(jīng)被暫停的Activity,比如執(zhí)行了onStop,優(yōu)先級(jí)最低。
當(dāng)系統(tǒng)內(nèi)存不足時(shí),系統(tǒng)就會(huì)按照上述優(yōu)先級(jí)去殺死目標(biāo)Activity所在的進(jìn)程,并在后續(xù)通過onSaveInstanceState和onRestoreInstanceState來存儲(chǔ)和恢復(fù)數(shù)數(shù)據(jù)。如果一個(gè)進(jìn)程中沒有四大組件在執(zhí)行,那么這個(gè)進(jìn)程將很快被系統(tǒng)殺死,因此,一些后臺(tái)工作不適合脫離四大組件而獨(dú)自運(yùn)行在后臺(tái)中,這樣進(jìn)程很容易被殺死。比較好的方法是將后臺(tái)工作放入Service中從而保證進(jìn)程有一定的優(yōu)先級(jí),這樣就不會(huì)輕易地被系統(tǒng)殺死。
3.強(qiáng)制不重新創(chuàng)建Activity,避免數(shù)據(jù)的保存和恢復(fù)
當(dāng)系統(tǒng)配置發(fā)生改變后,Activity會(huì)被重新創(chuàng)建,那么有沒有辦法不重新創(chuàng)建呢?答案是有的,接下來我們就來分析這個(gè)問題。系統(tǒng)配置中有很多內(nèi)容,如果當(dāng)某項(xiàng)內(nèi)容發(fā)生改變后,我們不想系統(tǒng)重新創(chuàng)建Activity,可以給Activity指定configChanges屬性。比如不想讓Activity在屏幕旋轉(zhuǎn)的時(shí)候重新創(chuàng)建,就可以給configChanges屬性添加orientation這個(gè)值,如下所示。

那么上圖中的keyboardHidden和screenSize是什么意思請(qǐng)參考下面的表格,這里不再贅述

ps:其實(shí)當(dāng)下我們手機(jī)里的app絕大多數(shù)已經(jīng)不支持橫屏操作,主要原因不僅僅是有些數(shù)據(jù)的保存和恢復(fù)很麻煩,還有一些圖片類的資源或者界面的布局需要根據(jù)橫屏重新繪制,無形增加了開發(fā)成本,這都是當(dāng)下企業(yè)開發(fā)app時(shí)不愿意看到的。
注:本文的部分內(nèi)容和圖片摘自互聯(lián)網(wǎng)