天天看點

Activity——生命周期一、生命周期全面分析二、各個生命周期狀态的說明三、生命周期的使用

一、生命周期全面分析

Android活動預設運作在目前程序所擁有的棧中,前台可見的活動則在活動棧的最頂部。其他背景活動則在棧的裡面,在正常的情況下(記憶體充足)其他的活動并沒有被回收或者殺死,它們仍然存在于棧中保持着原來的狀态。目前面的活動退出後,後面的活動就會搬到前台使得被使用者可見。如果在非正常情況下(記憶體緊張、按下Home鍵後右啟動其他應用)那麼棧内的非前台Activity就可能被回收,但是當我們傳回到該Activity時它又會被重新構造,并且會通過onSaveInstance和onRestoreInstance加載原來的資料使得它保持之前的狀态呈現給使用者。無論是正常情況,還是非正常情況下,這樣的實作都是基于一個非常重要的機制——生命周期。

1.什麼是生命周期

周期即活動從開始到結束所經曆的各種狀态。生命周期即活動從開始到結束所經曆的各個狀态。從一個狀态到另一個狀态的轉變,從無到有再到無,這樣一個過程中所經曆的狀态就叫做生命周期。

  • Acitivity本質上有四種狀态:
    1. 運作:如果一個活動被移到了前台(活動棧頂部)。
    2. 暫停:如果一個活動被另一個非全屏的活動所覆寫(比如一個Dialog),那麼該活動就失去了焦點,它将會暫停(但它仍然保留所有的狀态和成員資訊,并且仍然是依附在WindowsManager上),在系統記憶體積極缺乏的時候會将它殺死。
    3. 停止:如果一個活動被另一個全屏活動完全覆寫,那麼該活動處于停止狀态(狀态和成員資訊會保留,但是Activity已經不再依附于WindowManager了)。同時,在系統缺乏資源的時候會将它殺死(它會比暫停狀态的活動先殺死)。
    4. 重新開機:如果一個活動在處于停止或者暫停的狀态下,系統記憶體缺乏時會将其結束(finish)或者殺死(kill)。這種非正常情況下,系統在殺死或者結束之前會調用onSaveInstance()方法來儲存資訊,同時,當Activity被移動到前台時,重新啟動該Activity并調用onRestoreInstance()方法加載保留的資訊,以保持原有的狀态。

在上面的四中常有的狀态之間,還有着其他的生命周期來作為不同狀态之間的過度,用于在不同的狀态之間進行轉換,生命周期的具體說明見下。

二、各個生命周期狀态的說明

1.正常情況下的生命周期

  1. onCreate:與onDestroy配對,表示Activity正在被建立,這是生命周期的第一個方法。在這個方法中可以做一些初始化的工作(加載布局資源、初始化Activity所需要的資料等),耗時的工作在異步線程上完成。
  2. onRestart:表示Activity正在重新啟動。一般情況下,在目前Activity從不可見重新變為可見的狀态時onRestart就會被調用。這種情形一般是由于使用者的行為所導緻的,比如使用者按下Home鍵切換到桌面或者打開了一個新的Activity(這時目前Activity會暫停,也就是onPause和onStop被執行),接着使用者有回到了這個Activity,就會出現這種情況。
  3. onStart:與onStop配對,表示Activity正在被啟動,并且即将開始。但是這個時候要注意它與onResume的差別。兩者都表示Activity可見,但是onStart時Activity還正在加載其他内容,正在向我們展示,使用者還無法看到,即無法互動。
  4. onResume:與onPause配對,表示Activity已經建立完成,并且可以開始活動了,這個時候使用者已經可以看到界面了,并且即将與使用者互動(完成該周期之後便可以響應使用者的互動事件了)。
  5. onPause:與onResume配對,表示Activity正在暫停,正常情況下,onStop接着就會被調用。在特殊情況下,如果這個時候使用者快速地再回到目前的Activity,那麼onResume會被調用(極端情況)。一般來說,在這個生命周期狀态下,可以做一些存儲資料、停止動畫的工作,但是不能太耗時,如果是由于啟動新的Activity而喚醒的該狀态,那會影響到新Activity的顯示,原因是onPause必須執行完,新的Activity的onResume才會執行。
  6. onStop:與onStart配對,表示Activity即将停止,可以做一些稍微重量級的回收工作,同樣也不能太耗時(可以比onPause稍微好一點)。
  7. onDestroy:與onCreate配對,表示Activity即将被銷毀,這是Activity生命周期的最後一個回調,我們可以做一些回收工作和最終的資源釋放(如Service、BroadReceiver、Map等)。

    正常情況下,Activity的常用生命周期就是上面的7個,下圖更加詳細的描述的各種生命周期的切換過程:

    Activity——生命周期一、生命周期全面分析二、各個生命周期狀态的說明三、生命周期的使用

這裡要說的是,從上圖我們可以看到一個現象: 

onStart與onStop、onResume與onPause是配對的。兩種Activity回到前台的方式,從onPause狀态回到前台會走到onResume狀态,從onStop狀态回到前台會到onStart狀态,這是從是否可見和是否在前台來說的。從是否可見來說,onStart和onStop是配對的;從是否在前台來說,onResume和onPause是配對的。至于為什麼會有他們,在第三點生命周期的使用會說到。

我們來看看正常情況下生命周期的系統日志:

- :: -/com.example.david.lifecircle E/TAG: onCreate() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onStart() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onResume() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onPause() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onRestart() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onStart() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onResume() is invoked!
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.異常情況下的生命周期

一般正常情況的聲明周期就像上面所說的一樣,但是因為Android本身記憶體或者其他的一些情況會使得Activity不按照正常的生命周期。比如當資源配置發生改變、系統記憶體不足時,Activity就會被殺死。下面分析這兩種常見的情況。
           
  • 1
  • 2
  • 情況1:資源相關的系統配置發生改變導緻Activity被殺死并重新建立

    了解這個問題,我們首先要對系統的資源加載機制有一定了解,不過這裡我不分析系統資源加載機制了(因為我也不怎麼懂)。簡單說明一下,就像是我們把一張圖檔放在drawable目錄之後,就可以通過Resources去擷取這張圖檔。同時為了相容不同的裝置,我們還可能需要在其他的一些目錄放置不同的圖檔,比如 drawable-mdpi、drawable-hdpi等。這樣,當應用程式啟動時,系統就會根據目前裝置的情況去加載合适的Resource資源,比如說橫屏和豎屏的手機會拿到兩張不同的圖檔(設定了landscape或portrait狀态下的圖檔)。 

    如果說,目前Activity處于豎屏狀态,如果突然旋轉螢幕,由于系統配置發生了改變,在預設情況下,Activity就會被銷毀并重新建立(當然我們也可以組織系統重新建立,具體就在Mainfest中申明android:Configchanges=屬性即可)。

    異常情況下的調用流程:

    1. 調用onSaveInstance儲存目前Activity狀态。注意,它與onPause方法沒有先後之分。
    2. 調用onStop方法做後續處理。
    3. 調用onDestroy方法銷毀目前活動。
    4. 重新onCreate該活動。
    5. 調用onStart方法之後,再調用onRestoreInstance方法加載儲存的資料。
    6. 接下來就與正常的一樣了,調用onResume,然後運作。
    我們來看一下生命周期異常運作的系統日志:
- :: -/com.example.david.lifecircle E/TAG: onCreate() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onStart() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onResume() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onPause() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onSaveInstanceState() is invoked!  Save Text = Save Data
- :: -/com.example.david.lifecircle E/TAG: onCreate() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onStart() is invoked!
- :: -/com.example.david.lifecircle E/TAG: onRestoreInstanceState() is invoked!  Recover Text = Save Data
- :: -/com.example.david.lifecircle E/TAG: onResume() is invoked!
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 情況2:資源記憶體不足導緻低優先級的Activity被殺死

    這種情況不好模拟,但是其資料存儲和恢複過程和情況1完全一緻,這裡簡單的描述一下Activity的優先級情況。Activity的優先級從高到低可以大緻分為一下三種:

    (1)前台Activity——正在和使用者互動的Activity,優先級最高。 

    (2)可見但非前台Activity——比如Activity中彈出了一個對話框,導緻Activity可見但無法和使用者直接互動。 

    (3)背景Activity——已經被暫停或者停止的Activity,優先級最底。

    當系統記憶體不足的時候,系統就會按照上述優先級從低到高來殺死目标Activity。并在後續通過onSaveInstance和onRestoreInstance來存儲和恢複資料。 

    特别提醒的是:如果一個程序中沒有四大元件(Activity、Service、ContentProvider、BroadCastReceiver)。那麼這個程序就會很快被殺死,是以一些背景工作不适合脫離四大元件而獨立運作在背景中,否則很容易被殺死。一般是将背景工作放入Service中進而保證程序有一定的優先級,這樣才不會被系統輕易殺死。

三、生命周期的使用

1.常見的生命周期有關問題:

  1. onStart和onResume、onPause和onStop從描述上看來差不多,但是他們為什麼會分開呢?有什麼不同?
  2. 兩個Activity A和B,從A中啟動B,那麼B的onResume與A的onPause哪個會先執行呢?
  3. onSaveInstance與onRestoreInstance是任何情況下都可以使用的嘛?所有的儲存資料和恢複的操作都可以在這對方法中執行?
  4. 如上面所說,如何使得在系統配置放生改變後,Activity不被重新建立呢?

2.解析

1、 onStart和onResume、onPause和onStop這兩對看起來是差不多,而且很多時候都會同時調用onPause、onStop,然後回到onStart、onResume。但是在一些比較特殊的情況下就不一樣了。我們舉兩種情況, 

第一種:前台彈出了一個Dialog,那麼這個Dialog的作用隻是提醒使用者或者讓使用者輸入一個資訊等就完畢了,這是一個比較輕量級的任務; 

第二種:重新啟動另一個Activity界面,轉到另一個子產品。這時新啟動的Activity就不是一個臨時或者輕量級的任務了。 

這兩種情況,第一種一般很快就會傳回目前Activity,不會太耗時;第二種可能會很久,在這段時間内系統可能需要啟動其他的應用,那麼就會産生記憶體緊張的問題。是以,我認為是要區分這兩種情況,才會加入這兩對方法。在第一種情況下,可以在onPause中做一些較輕微的資料存儲,因為一般很快就會回到目前Activity;第二種情況下,适合在onStop中做一些較重量級的存儲。除此之外,我想不到其他的使用了。

2、這個問題可以從源碼中得到解答。不過源碼太複雜,涉及底層太多(AMS、Binder、ActivityStack、ActivityThread等)。不過可以直接調用生命周期,輸出系統日志來得到解答。從下面的日志我們可以看出,的确是要等到A活動的onPause方法之後B才能執行(這裡onCreate沒有輸出日志):

- :: -/com.example.david.lifecircle E/MainActivity: onCreate() is invoked!
- :: -/com.example.david.lifecircle E/MainActivity: onStart() is invoked!
- :: -/com.example.david.lifecircle E/MainActivity: onResume() is invoked!
- :: -/com.example.david.lifecircle E/MainActivity: onPause() is invoked!
- :: -/com.example.david.lifecircle E/SecondActivity: onStart() is invoked!
- :: -/com.example.david.lifecircle E/SecondActivity: onResume() is invoked!
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3、 onSaveInstance和onRestoreInstance是隻有Activity異常銷毀的時候才會調用的,是以這裡一般執行的是Activity異常銷毀時需要儲存和恢複的資料;onSaveInstance和onRestoreInstance方法還可以判斷Activity是否被重建,但正常情況下是不會調用的。是以正常情況下,還是應該在onPause和onStop方法中儲存資料。

4、上面提到,我們可以在AndroidMainfest.xml裡,對< activity />增加一個android:configChanges屬性,來指定在哪些配置改變的情況下Activity不需要重建。如下所示:

  • 1
我們在AndroidMainfest.xml做如下申明:
           
  • 1
  • 2
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.david.lifecircle">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:configChanges="orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity"></activity>
    </application>

</manifest>
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

MainActivity中的部分代碼:

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.e("MainActivity","onConfigurationChanged() is invoked!"+newConfig.orientation);
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e("MainActivity","onPause() is invoked!");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e("MainActivity","onResume() is invoked!");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e("MainActivity","onStart() is invoked!");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e("MainActivity","onRestart() is invoked!");
    }
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

點選螢幕旋轉,然後來看一下系統日志輸出:

- :: -/com.example.david.lifecircle E/MainActivity: onCreate() is invoked!
- :: -/com.example.david.lifecircle E/MainActivity: onStart() is invoked!
- :: -/com.example.david.lifecircle E/MainActivity: onResume() is invoked!
- :: -/com.example.david.lifecircle E/MainActivity: onConfigurationChanged() is invoked!
- :: -/com.example.david.lifecircle E/MainActivity: onConfigurationChanged() is invoked!
- :: -/com.example.david.lifecircle E/MainActivity: onConfigurationChanged() is invoked!
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我們發現,螢幕旋轉之後,并沒有重新調用生命周期,說明活動并沒有被重建。configChanges屬性還有許多的值,如:mcc\mnc\local\touchscreen\keyboard等等。

最後用一個實際的例子來說明Activity的各個生命周期。假設有一個程式由2個Activity A和B組成,A是這個程式的啟動界面。當使用者啟動程式時,Process和預設的Task分别被建立,接着A被壓入到目前的Task中,依次執行了 onCreate, onStart, onResume事件被呈現給了使用者;此時使用者選擇A中的某個功能開啟界面B,界面B被壓入目前Task遮蓋住了A,A的onPause事件執行,B的 onCreate, onStart, onResume事件執行,呈現了界面B給使用者;使用者在界面B操作完成後,使用Back鍵回到界面A,界面B不再可見,界面B的onPause, onStop, onDestroy執行,A的onResume事件被執行,呈現界面A給使用者。此時突然來電,界面A的onPause事件被執行,電話接聽界面被呈現給用 戶,使用者接聽完電話後,又按了Home鍵回到桌面,打開另一個程式“聯系人”,添加了聯系人資訊又做了一些其他的操作,此時界面A不再可見,其 onStop事件被執行,但并沒有被銷毀。此後使用者重新從菜單中點選了我們的程式,由于A和其所在的程序和Task并沒有被銷毀,A的onRestart 和onStart事件被執行,接着A的onResume事件被執行,A又被呈現給了使用者。使用者這次使用完後,按Back鍵傳回到桌面,A的 onPause, onStop被執行,随後A的onDestroy被執行,由于目前Task中已經沒有任何Activity,A所在的Process的重要程度被降到很 低,很快A所在的Process被系統結束 

常見的例子

情形一、一個單獨的Activity的正常的生命過程是這樣的:onCreate->onStart->onPause->onStop->onDestroy。例如:運作一個Activity,進行了一些簡單操作(不涉及頁面的跳轉等),然後按傳回鍵結束。

情形二、有兩個Activity(a和b),一開始顯示a,然後由a啟動b,然後在由b回到a,這時候a的生命過程應該是怎麼樣的呢(a被b完全遮蓋)?

a經曆的過程為onCreate->onStart->onResume->onPause->onStop->onRestart->onStart->onResume。這個過程說明了圖中,如果Activity完全被其他界面遮擋時,進入背景,并沒有完全銷毀,而是停留在onStop狀态,當再次進入a時,onRestart->onStart->onResume,又重新恢複。

情形三、基本情形同二一樣,不過此時a被b部分遮蓋(比如給b添加個對話框主題 android:theme=”@android:style/Theme.Dialog”)

a經曆的過程是:onCreate->onStart->onResume->onPause->onResume

是以當Activity被部分遮擋時,Activity進入onPause,并沒有進入onStop,從Activity2傳回後,執行了onResume

情形四、 打開程式,啟動a,點選a,啟動AlertDialog,按傳回鍵從AlertDialog傳回。

a經曆的過程是:onCreate->onStart->onResume

當啟動和退出Dialog時,Activity的狀态始終未變,,因為Dialog實際上時一個View,它是屬于某一個Activity的,是以如果Dialog顯示在目前Activity之前時不會影響到Activity的生命周期的。但是如果是其他Activity的Dialog彈出那麼就會觸發onPause()方法的執行。

轉載來源:https://blog.csdn.net/woshimalingyi/article/details/50961380