謹以文章記錄學習歷程,如有錯誤還請指明。
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開發相關的技術干貨,期待與你的交流,共勉。