Activity的生命周期分析

典型的生命周期的分析

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

activityLifeCircle.png

生命周期的四種狀態(tài)

  1. 運(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)。
  2. 暫停狀態(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)。
  3. 停止?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)回收。
  4. 銷毀狀態(tài):當(dāng)一個(gè)活動(dòng)從放回棧中移除后就變成了銷毀狀態(tài)。系統(tǒng)最傾向于回收這種活動(dòng),以保存內(nèi)存的充足。

生命周期的七種方法

  1. onCreate:表示Activity正在被創(chuàng)建,是活動(dòng)生命周期的第一個(gè)方法。在這個(gè)方法中,可以做些初始化工作,比如調(diào)用setContentView來加載界面布局資源,初始化Activity所需的數(shù)據(jù)等。
  2. onStart:表示活動(dòng)正在被啟動(dòng),即將開始,這時(shí)活動(dòng)已經(jīng)可見了,但是還沒有出現(xiàn)在前臺(tái),無法和用戶進(jìn)行交互。Activity已經(jīng)顯示,但我們并不能看到。
  3. onResume:表示活動(dòng)已經(jīng)可見。并且出現(xiàn)在前臺(tái)。
  4. 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í)行。
  5. onStop:表示Activity即將停止??梢宰錾晕⒅亓考?jí)的回收操作,但同樣不能太耗時(shí)。
  6. OnRestart:表示Activity正在被重新啟動(dòng)。一般情況下當(dāng)Activity從不可見重新變?yōu)榭梢姇r(shí),onRestart就會(huì)被調(diào)用。
  7. onDestroy:表示活動(dòng)即將被消耗,這是Activity生命周期的最后一個(gè)方法??梢栽谶@個(gè)方法進(jìn)行回收和最終的資源釋放。

onStart和onResume的區(qū)別

  1. 是否在前臺(tái)。onStart和onResume都是表示Activity可見,但是onStart時(shí)候Activity還在后臺(tái),到onResume時(shí)Activity才顯示到前臺(tái)。
  2. 職責(zé)不同。onStart方法中主要還是進(jìn)行初始化工作,而onResume方法,根據(jù)官方的建議,可以做開啟動(dòng)畫和獨(dú)占設(shè)備的操作。

onPause和onStop的區(qū)別

  1. 如果啟動(dòng)的新活動(dòng)是一個(gè)對(duì)話框的活動(dòng),則onPause方法會(huì)得到執(zhí)行,而不執(zhí)行onStop方法。
  2. 在系統(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。

  1. 啟動(dòng)一個(gè)MainActivity回調(diào):onCreate->onStart->onResume.

  2. 切換到桌面時(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)建。其生命周期如下:

flow.png

當(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í)可分為如下三種:

  1. 前臺(tái)Activity——正在和用戶交互的Activity,優(yōu)先級(jí)最高

  2. 可見但非前臺(tái)Activity——比如Activity中彈出一個(gè)對(duì)話框,導(dǎo)致Activity調(diào)用onPause方法后可見但是位于后臺(tái)無法跟用戶直接交互

  3. 后臺(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ù)探索》《第一行代碼》

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

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