典型的生命周期的分析
Activity生命周期是指一個(gè)Activity從創(chuàng)建到銷毀的全過程。下圖是Activity經(jīng)典的生命周期模型。

生命周期的四種狀態(tài)
- 運(yùn)行狀態(tài):當(dāng)一個(gè)活動(dòng)位于返回棧的棧頂時(shí),這時(shí)活動(dòng)就位于運(yùn)行狀態(tài)。系統(tǒng)最不愿意回收的就是處于運(yùn)行狀態(tài)的活動(dòng)。
- 暫停狀態(tài):當(dāng)一個(gè)活動(dòng)不再位于棧的棧頂時(shí),但仍然可見時(shí),這時(shí)活動(dòng)就進(jìn)入了暫停狀態(tài)。比如對(duì)話框形式的活動(dòng)。處于暫停的活動(dòng)仍然是完全存活的,系統(tǒng)在內(nèi)存極低的情況下會(huì)考慮回收這種活動(dòng)。
- 停止?fàn)顟B(tài):當(dāng)一個(gè)活動(dòng)不再處于棧頂位置,且活動(dòng)完全不可見時(shí),就進(jìn)入了停止?fàn)顟B(tài)。處于這種狀態(tài)的活動(dòng)很可能被系統(tǒng)回收。
- 銷毀狀態(tài):當(dāng)一個(gè)活動(dòng)從放回棧中移除后就變成了銷毀狀態(tài)。系統(tǒng)最傾向于回收這種活動(dòng),以保存內(nèi)存的充足。
生命周期的七種方法
- onCreate:表示Activity正在被創(chuàng)建,是活動(dòng)生命周期的第一個(gè)方法。在這個(gè)方法中,可以做些初始化工作,比如調(diào)用setContentView來加載界面布局資源,初始化Activity所需的數(shù)據(jù)等。
- onStart:表示活動(dòng)正在被啟動(dòng),即將開始,這時(shí)活動(dòng)已經(jīng)可見了,但是還沒有出現(xiàn)在前臺(tái),無法和用戶進(jìn)行交互。Activity已經(jīng)顯示,但我們并不能看到。
- onResume:表示活動(dòng)已經(jīng)可見。并且出現(xiàn)在前臺(tái)。
- onPause:表示Activity正在停止,正常情況下,緊接著onStop方法會(huì)執(zhí)行。但在特殊情況下,如果這時(shí)候快速回到當(dāng)前活動(dòng),那么會(huì)調(diào)用onResume??梢栽谶@個(gè)方法進(jìn)行一些存儲(chǔ)數(shù)據(jù)、停止動(dòng)畫等輕量級(jí)的操作,但是不能太耗時(shí),因?yàn)檫@會(huì)影響新Activity的顯示。因?yàn)橹挥信fActivity的onPause方法執(zhí)行后,新活動(dòng)的onResume才能被執(zhí)行。
- onStop:表示Activity即將停止??梢宰錾晕⒅亓考?jí)的回收操作,但同樣不能太耗時(shí)。
- OnRestart:表示Activity正在被重新啟動(dòng)。一般情況下當(dāng)Activity從不可見重新變?yōu)榭梢姇r(shí),onRestart就會(huì)被調(diào)用。
- onDestroy:表示活動(dòng)即將被消耗,這是Activity生命周期的最后一個(gè)方法??梢栽谶@個(gè)方法進(jìn)行回收和最終的資源釋放。
onStart和onResume的區(qū)別
- 是否在前臺(tái)。onStart和onResume都是表示Activity可見,但是onStart時(shí)候Activity還在后臺(tái),到onResume時(shí)Activity才顯示到前臺(tái)。
- 職責(zé)不同。onStart方法中主要還是進(jìn)行初始化工作,而onResume方法,根據(jù)官方的建議,可以做開啟動(dòng)畫和獨(dú)占設(shè)備的操作。
onPause和onStop的區(qū)別
- 如果啟動(dòng)的新活動(dòng)是一個(gè)對(duì)話框的活動(dòng),則onPause方法會(huì)得到執(zhí)行,而不執(zhí)行onStop方法。
- 在系統(tǒng)內(nèi)存不足的時(shí)候可能不會(huì)執(zhí)行onStop方法,因此程序狀態(tài)的保存、獨(dú)占設(shè)備和動(dòng)畫的關(guān)閉、以及一些數(shù)據(jù)的保存最好在onPause中進(jìn)行,但要注意不能太耗時(shí)。
具體情況
前提:兩個(gè)活動(dòng): MainActivity,SecondActivity。
啟動(dòng)一個(gè)MainActivity回調(diào):onCreate->onStart->onResume.
切換到桌面時(shí),MainActivity回調(diào):onPause->onStop;重新回到MainActivity,MainActivity回調(diào):onRestart->onStart->onResume。
-
- MainActivity啟動(dòng)SecondActivity : onPause(MainActivity) -> onCreate(SecondActivity) -> onStart(SecondActivity) -> onResume(SecondActivity) -> onStop(MainActivity)。
- 按下返回鍵:onPause(SecondActivity) -> onRestart(MainActivity) -> onStart(MainActivity) -> onResume(MainActivity) -> onStop(SecondActivity) -> onDestroy(SecondActivity)
注意:如果SecondActivity采用了透明主題,那么MainActivity不會(huì)回調(diào)onStop
從上面的情況我們可以很明顯的發(fā)現(xiàn)舊Activity的onPause調(diào)用后,新Actiivty才能被啟動(dòng)。故在onPause和onStop方法中都不能進(jìn)行耗時(shí)操作,尤其是onPause,這就意味著我們盡量在onStop中操作,從而使新Activity盡快的顯示并切換到前臺(tái)來。
異常情況下的生命周期的分析
情況1:資源相關(guān)的系統(tǒng)配置發(fā)生改變導(dǎo)致Activity殺死并重新創(chuàng)建
這個(gè)情況最常見的就是旋轉(zhuǎn)手機(jī)屏幕。假設(shè)當(dāng)前Activity處于豎屏狀態(tài),這時(shí)候我們突然旋轉(zhuǎn)屏幕,由于系統(tǒng)配置發(fā)生了改變,默認(rèn)情況下,Activity就會(huì)被銷毀并重新創(chuàng)建。其生命周期如下:

當(dāng)系統(tǒng)配置改變時(shí),Activity首先會(huì)被銷毀,其onPause,onStop,onDestroy都會(huì)被執(zhí)行。同時(shí)由于Activity是被異常終止的,所以系統(tǒng)會(huì)調(diào)用onSaveInstanceState來保存Activity的狀態(tài)。這個(gè)方法只有活動(dòng)在異常情況下終止才會(huì)被調(diào)用(比如鎖屏也是會(huì)調(diào)用onSaveInstanceState的,但不會(huì)執(zhí)行onDestroy,故數(shù)據(jù)不會(huì)丟失)。當(dāng)Activity重新創(chuàng)建時(shí),會(huì)把onSaveInstanceState方法保存的Bundle對(duì)象作為參數(shù)傳給onCreate和onRestoreInstanceState方法,故在重建時(shí)可以在onCreate取出Bundle對(duì)象并恢復(fù),另外onRestoreInstanceState方法是在onStart之后調(diào)用。
保存Activity狀態(tài)
值得一提的是,在Activity異常情況重新創(chuàng)建后,在onSaveInstanceState和onCreate方法中,系統(tǒng)會(huì)為我們做了一定的恢復(fù)工作。比如文本框中用戶輸入的數(shù)據(jù),ListView滾動(dòng)的位置等。但是如果您的Activity可能需要包含更多要恢復(fù)的狀態(tài)信息,這時(shí)候就可以在onSaveInstanceState方法中添加鍵值對(duì)Bundle來保存你的Activity狀態(tài)。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "onSaveInstanceState");
outState.putInt(KEY_NUM,1215);
}
恢復(fù)Activity狀態(tài)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState != null){
int num = savedInstanceState.getInt(KEY_NUM);
Log.d(TAG, "MainActivity: [onCreate]:"+num);
}
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
int num = savedInstanceState.getInt(KEY_NUM);
Log.d(TAG, "[onRestoreInstanceState]:"+num);
}
上面提供了兩種恢復(fù)狀態(tài)的方法。因?yàn)楫?dāng)Activity異常銷毀重建后,接受的位置可以是onCreate和onRestoreInstanceState,然后在去獲取之前存儲(chǔ)的數(shù)據(jù)。兩者的區(qū)別主要在于:onCreate是正常啟動(dòng)的話,savedInstanceState是為null的,故要做判空處理,而onRestoreInstanceState一旦被調(diào)用,savedInstanceState一定是有值的,所以不需要做額外的判空。雖然說兩種方法都可以進(jìn)行恢復(fù)數(shù)據(jù),但官方文檔的建議是采用onRestoreInstanceState去恢復(fù)數(shù)據(jù)。
情況2:資源內(nèi)存不足導(dǎo)致低優(yōu)先級(jí)的Activity被殺死
Activity優(yōu)先級(jí)可分為如下三種:
前臺(tái)Activity——正在和用戶交互的Activity,優(yōu)先級(jí)最高
可見但非前臺(tái)Activity——比如Activity中彈出一個(gè)對(duì)話框,導(dǎo)致Activity調(diào)用onPause方法后可見但是位于后臺(tái)無法跟用戶直接交互
后臺(tái)Activity——已經(jīng)被暫停的Activity,比如已經(jīng)執(zhí)行了onStop,優(yōu)先級(jí)最低
當(dāng)系統(tǒng)內(nèi)存不足時(shí),就會(huì)按照優(yōu)先級(jí)低到高的順序殺死Activity所在的進(jìn)程,并通過onSaveInstanceState和onRestoreInstanceState方法來存儲(chǔ)和恢復(fù)數(shù)據(jù)。需注意,如果一個(gè)進(jìn)程在沒有四大組件的地方執(zhí)行,會(huì)很容易被殺死,因此一些后臺(tái)工作不適合脫離四大組件獨(dú)自運(yùn)行在后臺(tái)中。推薦的方法是將后臺(tái)工作放入到Service中從而保證有一定的優(yōu)先級(jí),不容易被系統(tǒng)殺死
configChanges:不重新創(chuàng)建Activity
當(dāng)我們不想在系統(tǒng)配置發(fā)生改變后重新創(chuàng)建活動(dòng),可以為Activity指定configChanges屬性。比如不想讓Activity在屏幕旋轉(zhuǎn)的時(shí)候重新創(chuàng)建,可以在AndroidMenifest.xml中指定configChanges屬性
android:configChanges = "orientation"
設(shè)置完屬性后,當(dāng)你的屏幕旋轉(zhuǎn)后,你會(huì)發(fā)現(xiàn)Activity并沒有調(diào)用onSaveInstanceState和onRestoreInstanceState來存儲(chǔ)和恢復(fù)數(shù)據(jù),而是系統(tǒng)調(diào)用了Activity中的onConfigurationChanged方法,故此時(shí)我們就可以在這個(gè)方法中做相應(yīng)的操作。
參考:《Android開發(fā)藝術(shù)探索》《第一行代碼》