1. 程式人生 > >Android Activity生命週期詳解

Android Activity生命週期詳解

Activity作為Android的四大元件之一,非常的重要,也是最常用的四大元件,使用Activity必須要在AndroidManifest中進行註冊,那麼作為Android的基礎,Activity的生命週期你是否完全掌握了呢?下面就讓我們來一起回顧一下Activity的生命週期吧!

首先,你需要知道 Activity的生命週期分為兩種。

  1. 典型情況下的生命週期(就是我們開發中經常用到的)
  2. 異常情況下的生命週期(雖說開發中也會用到,但是並不是所有的專案都會去(需要)回撥異常生命週期的方法)

所以我們先來介紹前者,因為後者出現的情況比較特殊。

  • 典型情況下的生命週期。官網的流程圖肯定是要看的,一張圖包含了一個Activity從建立到銷燬所經歷的一切

先總結一下有什麼生命週期回撥方法以及各個生命週期回撥方法都是代表什麼意思。

  1. onCreate:在首次建立 Activity 時呼叫。系統向此方法傳遞一個 Bundle 物件,其中包含 Activity 的上一狀態,不過前提是捕獲了該狀態,而後會呼叫onStart方法。可以在此方法中執行所有正常的靜態設定 ,比如:建立檢視、將資料繫結到列表等等。
  2. onStart:在 Activity 即將對使用者可見之前呼叫。而後如果Activity轉入了前臺就會呼叫onResume方法。 如果此時直接螢幕熄滅或者使用者按下home鍵則會直接呼叫onStop方法,當然這種情況比較極端。
  3. onResume:
    在 Activity 即將開始與使用者進行互動之前呼叫。 此時,Activity 處於 Activity 堆疊的頂層,並具有使用者輸入焦點。當跳轉另一個Activity,或者退出當前Activity後會呼叫onPause方法。
  4. onPause:在系統即將開始繼續另一個 Activity 時呼叫。 此方法通常用於確認對永續性資料的未儲存更改、停止動畫以及其他可能消耗 CPU 的內容,諸如此類。 它應該非常迅速地執行所需操作,因為它返回後,下一個 Activity 才能繼續執行,所以不能執行耗時操作。而後正常情況下會呼叫onStop方法。但是有一種極端情況,就是如果這個時候快速讓 當前Activity 返回前臺,則會呼叫onResume方法。
  5. onStop:在 Activity 對使用者不再可見時呼叫。如果 Activity 被銷燬,或另一個 Activity(一個現有 Activity 或新 Activity)繼續執行並將其覆蓋,就會呼叫此方法。而後如果 Activity 恢復與使用者的互動,則會呼叫 onRestart 方法,如果 Activity 被銷燬,則會呼叫onDestroy方法。
  6. onRestart:在Activity被停止後再次啟動時呼叫(即螢幕熄滅後再次回到app,按下home鍵後再次回到app),而後會呼叫onStart方法。
  7. onDestroy:在 Activity 被銷燬前呼叫,這是 Activity 收到的最後呼叫。 當 Activity 結束(對 Activity 呼叫了 finish 方法),或系統為節省空間而暫時銷燬該 Activity 例項時,可能會呼叫它。 你可以通過 isFinishing 方法區分這兩種情形。

程式碼驗證:

  • 程式碼
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    LogUtils.d(TAG,"onCreate ---> 建立時呼叫");
}

@Override
protected void onRestart() {
    super.onRestart();
    LogUtils.d(TAG,"onRestart ---> 重啟時呼叫");
}

@Override
protected void onStart() {
    super.onStart();
    LogUtils.d(TAG,"onStart ---> 即將可見不可互動時呼叫");
}

@Override
protected void onResume() {
    super.onResume();
    LogUtils.d(TAG,"onResume ---> 可見可互動時呼叫");
}

@Override
protected void onPause() {
    super.onPause();
    LogUtils.d(TAG,"onPause ---> 即將暫停時呼叫");
}

@Override
protected void onStop() {
    super.onStop();
    LogUtils.d(TAG,"onStop ---> 即將停止不可見時呼叫");
}

@Override
protected void onDestroy() {
    super.onDestroy();
    LogUtils.d(TAG,"onDestroy ---> 即將銷燬時呼叫");
}
  • 驗證結果

  1.正常進入Activity的生命週期log日誌。

V/MAIN_ACTIVITY: onCreate ---> 建立時呼叫
V/MAIN_ACTIVITY: onStart ---> 即將可見不可互動時呼叫
V/MAIN_ACTIVITY: onResume ---> 可見可互動時呼叫

    2.點選物理返回鍵正常退出Activity的生命週期log日誌。(長按home鍵退出應用不走onDestroy回撥方法,但是會走onSaveInstanceState方法,後面會講

V/MAIN_ACTIVITY: onPause ---> 即將暫停時呼叫
V/MAIN_ACTIVITY: onStop ---> 即將停止不可見時呼叫
V/MAIN_ACTIVITY: onDestroy ---> 即將銷燬時呼叫

    3.正常進入Activity,點選home鍵返回手機主介面的生命週期log日誌。

V/MAIN_ACTIVITY: onCreate_A ---> 建立時呼叫
V/MAIN_ACTIVITY: onStart_A ---> 即將可見不可互動時呼叫
V/MAIN_ACTIVITY: onResume_A ---> 可見可互動時呼叫
V/MAIN_ACTIVITY: onPause_A ---> 即將暫停時呼叫
V/MAIN_ACTIVITY: onStop_A ---> 即將停止不可見時呼叫

    4.長按home鍵再次回到 Activity  的生命週期log日誌。

V/MAIN_ACTIVITY: onRestart_A ---> 重啟時呼叫
V/MAIN_ACTIVITY: onStart_A ---> 即將可見不可互動時呼叫
V/MAIN_ACTIVITY: onResume_A ---> 可見可互動時呼叫

    5.正常進入Activity_A,啟動另一個Activity_B 的生命週期log日誌。

V/MAIN_ACTIVITY: onCreate_A ---> 建立時呼叫
V/MAIN_ACTIVITY: onStart_A ---> 即將可見不可互動時呼叫
V/MAIN_ACTIVITY: onResume_A ---> 可見可互動時呼叫
V/MAIN_ACTIVITY: onPause_A ---> 即將暫停時呼叫
V/MAIN_ACTIVITY: onCreate_B ---> 建立時呼叫
V/MAIN_ACTIVITY: onStart_B ---> 即將可見不可互動時呼叫
V/MAIN_ACTIVITY: onResume_B ---> 可見可互動時呼叫
V/MAIN_ACTIVITY: onStop_A ---> 即將停止不可見時呼叫

6.按下物理返回鍵再次回到Activity_A的生命週期log日誌。

V/MAIN_ACTIVITY: onPause_B ---> 即將暫停時呼叫
V/MAIN_ACTIVITY: onRestart_A ---> 重啟時呼叫
V/MAIN_ACTIVITY: onStart_A ---> 即將可見不可互動時呼叫
V/MAIN_ACTIVITY: onResume_A ---> 可見可互動時呼叫
V/MAIN_ACTIVITY: onStop_B ---> 即將停止不可見時呼叫
V/MAIN_ACTIVITY: onDestroy_B ---> 即將銷燬時呼叫

總結:可以清晰地看到,Avtivity的整個生命週期是發生在 onCreate 方法 和 onDestroy 方法之間的。其中可見生命週期是發生onStart 方法和 onStop 方法之間的,也就是使用者可以在介面看到Activity並且可以互動的狀態。前臺生命週期是發生在onResume 方法和 onPause 方法之間的,這個狀態下Activity位於所有的Activity之上,並且可以和使用者互動。

備註:因為如果跳轉下一個Activity時系統會先呼叫上一個Activity的onPause方法,所以一定不能在onPause方法中進行耗時操作!

  • 異常情況下的生命週期。 (Activity被系統回收或者當前裝置的配置發生了變化“例如橫屏”,從而導致Activity被銷燬重建,我們來看下官網流程圖)

先總結一下有什麼生命週期回撥方法以及各個生命週期回撥方法都是代表什麼意思。

    1.onSaveInstanceState:當系統為了恢復記憶體而銷燬某項 Activity 時,Activity物件也會被銷燬,因此係統在繼續 Activity 時根本無法讓其狀態保持完好,而是必須在使用者返回 Activity 時重建 Activity 物件。但使用者並不知道系統銷燬 Activity 後又對其進行了重建,因此他們很可能認為 Activity 狀態毫無變化。 在這種情況下,你可以實現onSaveInstanceState回撥方法對有關 Activity 狀態的資訊進行儲存,以確保有關 Activity 狀態的重要資訊得到保留。

呼叫時機:當用戶按下HOME鍵時、長按HOME鍵,選擇執行其他的程式時、按下電源按鍵(關閉螢幕顯示)時、從activity A中啟動一個新的activity時、螢幕方向切換時,例如從豎屏切換到橫屏時。

    2.onRestoreInstanceState 或者 onCreate:系統會先呼叫onSaveInstanceState方法,然後銷燬 Activity。系統會向該方法傳遞一個Bundle 物件,你可以在其中使用putString和 putInt 等方法以鍵-值對形式儲存有關 Activity 狀態的資訊。然後,如果系統終止您的應用程序,並且使用者返回您的 Activity,則系統會重建該 Activity,並將Bundle同時傳遞給onCreate和onRestoreInstanceState。您可以使用上述任一方法從Bundle提取您儲存的狀態並恢復該 Activity 狀態。如果沒有狀態資訊需要恢復,則傳遞給您的Bundle是空值(如果是首次建立該 Activity,就會出現這種情況)。

解析流程圖:可以看到,從Activity running開始走,Activity 重獲使用者焦點時可保持狀態完好。恢復資料的方式跟隨生命週期的不同有兩種情況。

  1. 系統在銷燬 Activity 後重建 Activity,Activity 必須恢復之前儲存的狀態。
  2. 系統停止 Activity 後繼續執行 Activity,並且 Activity 狀態保持完好。

程式碼驗證:

  • 程式碼
@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if (outState != null){
        outState.putString("TEST","test");
        LogUtils.d(TAG2,"onSaveInstanceState ---> 異常銷燬時呼叫");
    }

}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    if (savedInstanceState != null){
        String test = savedInstanceState.getString("TEST");
        LogUtils.d(TAG2,"onRestoreInstanceState ---> 恢復資料時呼叫 --> " + test);
    }
}
  • 驗證結果

    1.旋轉手機螢幕檢視log日誌。

V/MAIN_ACTIVITY2: onSaveInstanceState ---> 異常銷燬時呼叫
V/MAIN_ACTIVITY2: onRestoreInstanceState ---> 恢復資料時呼叫 --> test

總結:注意:onSaveInstanceState的呼叫時序在onStop之前,但是和onPause 的呼叫時序就不一定了,有可能在onPause之前或者之後。又因為無法保證系統會呼叫onSaveInstanceState(存在不需要儲存狀態的情況,例如使用者使用“返回”按鈕離開您的 Activity 時,因為使用者的行為是在顯式關閉 Activity),因此您只應利用它來記錄 Activity 的瞬態(UI 的狀態)切勿使用它來儲存永續性資料,而應使用onPause在使用者離開 Activity 後儲存永續性資料,例如應儲存到資料庫的資料。

備註:

  1. 當 Activity 暫停或停止時(使用者按下hoem鍵或者螢幕熄滅),Activity 的狀態會得到保留。 確實如此,因為當 Activity 暫停或停止時,Activity物件仍保留在記憶體中 ,有關其成員和當前狀態的所有資訊仍處於活動狀態。 因此,使用者在 Activity 內所做的任何更改都會得到保留,這樣一來,當 Activity 返回前臺(當它“繼續”)時,這些更改仍然存在,所以,即使您什麼都不做,也不實現onSaveInstanceState,Activity類的 onSaveInstanceState預設實現也會恢復部分 Activity 狀態。具體地講,預設實現會為佈局中的每個View 呼叫相應的onSaveInstanceState方法,讓每個檢視都能提供有關自身的應儲存資訊。Android 框架中幾乎每個小部件都會根據需要實現此方法,以便在重建 Activity 時自動儲存和恢復對 UI 所做的任何可見更改。例如,EditText 小部件儲存使用者輸入的任何文字,CheckBox小部件儲存複選框的選中或未選中狀態。您只需為想要儲存其狀態的每個小部件提供一個唯一的 ID(通過 android:id  屬性)。如果小部件沒有 ID,則系統無法儲存其狀態。(預設情況下系統不會恢復儲存成員值(變數))
  2. 你只需旋轉裝置,讓螢幕方向發生變化,就能有效地測試您的應用的狀態恢復能力。 當螢幕方向變化時,系統會銷燬並重建 Activity,以便應用可供新螢幕配置使用的備用資源。

歡迎加入Q群一起探討Android問題。