詳解Activity&Fragment生命周期

謹以文章記錄學習歷程,如有錯誤還請指明。

Activity生命周期

首先放上Google Develop Guides中的Activity完整的生命周期示意圖:


回調初步解讀

  • onCreate():創建活動時調用。

  • onStart():當活動進入可見狀態時調用,使得活動可見但不可與用戶交互。

  • onResume():活動進入前臺時調用,可與用戶交互。

  • onPause():活動不持有用戶焦點但依然可見時調用。活動仍可見,但停止與用戶交互,比如彈窗,鎖屏等

  • onStop():活動不可見時調用

  • onDestroy():活動退出,被銷毀時調用

  • onRestart():活動由不可見重新返回前臺時調用。依次調用onRestart()->onStart()->onResume()

回調方法中進行的操作

  • onCreate():在這個方法中,執行基本的應用程序啟動邏輯,這種邏輯應該只在活動的整個生命周期中發生一次。如將數據綁定到ListView,聲明范圍變量等。同時該方法接收一個savedInstanceState參數,是用來恢復之前保存過狀態的Bundle對象。后面我們會介紹。

  • onStart():該方法中初始化維護UI的組件,如注冊一個監聽UI變化的廣播。

  • onResume():在這個方法中,應該初始化在onPause()中釋放的組件,如初始化camera,同時執行活動每次進入前臺時候都需要的初始化操作,如開始動畫與初始化哪些只有在獲取用戶焦點時才需要得到組件,如上下文菜單。

  • onPause():釋放系統資源,例如廣播接收器、處理傳感器(如GPS)或任何可能影響電池壽命的資源。

  • onStop():釋放幾乎所有不需要的資源,如上述onStart()中創建的廣播,同時在此方法中執行耗時的釋放資源的操作,如保存數據,網絡調用,數據庫事務等。同時很重要的一點,需要在此方法中釋放可能導致內存泄漏的資源,因為系統因為內存緊張而殺死活動進程時,不會調用最后的onDestroy()方法。

  • onDestroy():釋放在onCreate()中初始化的活動所能使用的全局資源。

在任何一個生命周期回調方法中調用finish()方法時,系統會直接調用onDestroy()方法,而跳過這之前的所有回調過程。

  • onRestart():由于onStart()的存在,這個方法好像沒什么使用場景。

為什么在onStop()中釋放耗時資源而不是在onPause()中?
原因:在兩個Activity A,B中,當從A中startActivity()startActivityForResult()啟動B時,分別以如下的順序調用生命周期的回調方法:

  • Activity A的onPause()
  • Activity B的onCreate()onStart()onResume()依次執行,此時Activity B進入前臺并獲得用戶焦點
  • 如果Activity A不再顯示在屏幕上,則調用其onStop()方法。

A的onStop()方法和B的onCreate()等一系列方法并非順序執行,而是有重疊。因此當onPause()方法中進行耗時操作時,會嚴重影響活動之間的跳轉速度

不同場景下回調方法的調用順序

  • 啟動Activity
    onCreate()(創建)---> onStart()(可見,不可交互) ---> onResume()(前臺,可交互)

  • currentActivity被otherActivity覆蓋一部分,或鎖屏
    onPause()(失去用戶焦點,但仍可見)

  • currentActivity由上述部分不可見狀態回到前臺或解鎖屏幕
    onResume()(前臺,持有用戶焦點)

  • currentActivity轉到otherActivity界面,或按Home退回主界面,自身進入后臺
    onPause()(失去用戶焦點,但仍可見)---> onStop()(不可見)

  • 由上述后臺狀態再次打開該活動
    onRestart()(過渡狀態,不清楚到底有什么用。。。) ---> onStart()(可見,不可交互) ---> onResume()(前臺,持有用戶焦點)

  • currentActivity部分可見或后臺不可見時,系統內存不足時
    殺死當前Activity,此時生命周期不會發生回調

  • 上述被殺死的活動再次啟動
    onCreate()(重新創建) ---> onStart()(可見,不可交互) ---> onResume()(前臺,持有用戶焦點)

  • 用戶退出currentActivity
    onPause()(失去用戶焦點,但仍可見) ---> onStop()(不可見) ---> onDestroy()

  • 多窗口下,ActivityA獲得焦點時,點擊ActivityB
    對于ActivityA:onPause()(失去用戶焦點,但仍可見)
    對于ActivityB:onResume()(前臺,持有用戶焦點)


Fragment的生命周期

同樣,還是先放上Google Develop Guides中的Fragment完整的生命周期示意圖:


回調解析

Activity中同名方法不在贅述

  • onAttach()
    Fragment和Activity建立關聯時調用(獲得activity的傳遞的值,如二者依靠回調通信時,獲得activity的引用(將其轉型為callback回調接口))

  • onCreateView()
    為Fragment創建視圖(加載布局)時調用(給當前的fragment繪制UI布局,可以使用線程更新UI)

  • onActivityCreated()
    當Activity中的onCreate()方法執行完后調用(表示activity執行oncreate()方法完成了的時候會調用此方法)

  • onDestroyView()
    Fragment中的布局被移除時調用

  • onDetach()
    Fragment和Activity解除關聯的時候調用

不同場景下回調方法的調用順序

  • 創建一個fragment的時候
    創建過程:onAttach() ---> onCreate() ---> onCreateView() ---> onActivityCreated()
    顯示到前臺:onStart() ---> onResume()

  • fragment進入后臺
    onPause() ---> onStop()

  • fragment被銷毀
    onPause() ---> onStop() ---> onDestroyView() ---> onDestroy() ---> onDetach()

  • 鎖屏
    onPause() ---> onStop()

  • 解鎖
    onStart() ---> onResume()

  • 打開其他fragment(原始fragment被替換,或完全不可見)
    onPause() ---> onStop() ---> onDestroyView()

  • 上述條件下back回原始fragment
    onCreateView() ---> onActivityCreated() -> onStart()---> onResume()

  • Home回到桌面
    onPause() ---> onStop()

  • 上述回到原始fragment
    onStart() ---> onResume()

  • 退出應用
    onPause() ---> onStop() --->onDestroyView()---> onDestroy() --->onDetach()


二者生命周期的聯系

老規矩,還是放上Google Develop Guides中的對比圖

生命周期對比

由于Android內部機制(原理尚不知,未深入源碼做研究),fragment總是依附于activity而存在,不過需要注意的是activity的生命周期由系統控制,而fragment則是由宿主activity控制,因此在activity進入到某一狀態如created,系統會調用activity的onCreate(),此時宿主activity會調用fragment的onAttach()...onActivityCreated()一系列方法,使得fragment快速跟上宿主,與宿主activity保持一致狀態。


關于Activity狀態保存與恢復

在上述生命周期中,我們有時會需要保存activity的狀態,比如我們正在某一文本框EditText中輸入文本時,此時退出應用之后再次打開時,我們會發現文本框的內容消失了。消失了。。消失了。。。
這種情況下,用戶體驗顯然不會好。因此Google引入了保存UI狀態這一概念。

保存狀態

復寫onSaveInstanceState(),傳入一個帶有狀態信息的Bundle對象,代碼如下:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);


    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

保存狀態的時機

Activity容易被銷毀的時候調用:

  • 按下Home鍵:Activity進入了后臺
  • 鎖屏:Activity進入后臺
  • 啟動其他Activity:Activity進入后臺
  • 橫豎屏切換:銷毀并重建Activity實例

上述場景下,多數為當系統內存不足時,可能銷毀后臺低優先級的Activity。

注意事項

在用戶主動銷毀Activity時不會保存狀態:

  • back
  • 調用finish()方法

方法調用時機:

  • Android P之前:介于onStop()之前,但不確定在onPause()之前還是之后。
  • Android P中:在onStop()后調用

設有id的組件會自動保存組件的狀態

恢復狀態

我們有兩種方式恢復狀態:

  • onCreate()方法恢復
    需要注意的是,在嘗試讀取該對象時,需要判斷其是否為空,空時則會創建該活動的新實例,而非恢復之前被銷毀活動實例:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first


    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    // ...
}
  • 重寫onRestoreInstanceState()方法恢復
    只有在有待恢復的狀態時,系統才調用onRestoreInstanceState(),所以不需要檢查savedInstanceState是否為空:
public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

調用時機

  • 銷毀了之后重建的時候調用, 如果內存充足, 系統沒有銷毀這個 Activity, 就不需要調用
  • 橫豎屏切換時調用

總結

  • 本文盡可能詳細的對Activity和Fragment的生命周期,以及Activity的狀態保存與恢復作出了解析
  • 筆者水平有限,如有錯漏,歡迎指正。
  • 接下來我也會將所學的知識分享出來,有興趣可以繼續關注whd_Alive的Android開發筆記

歡迎關注whd_Alive的簡書

  • 不定期分享Android開發相關的技術干貨,期待與你的交流,共勉。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容