Android Activity 生命周期
官方文檔 https://developer.android.google.cn/guide/components/activities/activity-lifecycle
核心回調(diào)
- 6 個(gè)核心的生命周期
onCreate —— onStart 可見(jiàn) —— onResume 有焦點(diǎn) —— onPause 無(wú)焦點(diǎn) —— onStop 不可見(jiàn) —— onDestory
- onRestart 回調(diào)方法是在 Activity 從不可見(jiàn)(onStop)重新回到前臺(tái)時(shí)調(diào)用的
- 所有生命周期回調(diào)方法重寫(xiě)時(shí)必須調(diào)用其父類(lèi)方法
- 由于 Activity 經(jīng)常在暫停和恢復(fù)之間來(lái)回切換,所以 onResume 和 onPause 的邏輯應(yīng)該是輕量級(jí)的
- 圖中顯示系統(tǒng)在某些情況下回收內(nèi)存導(dǎo)致 onStop 和 onDestory 可能不被調(diào)用,因此可以根據(jù)實(shí)際情況在 onPause 中保存一些非常重要的數(shù)據(jù),耗時(shí)操作需要開(kāi)子線程處理
經(jīng)典場(chǎng)景
- 1 第一次啟動(dòng) Activity A
//Activity A
onCreate -> onStart -> onResume
- 2 在 Activity A 上啟動(dòng) Activity B
//Activity A,如果 Activity B 是完全透明或是對(duì)話框主題的話,那么 A 就不繼續(xù)走 onStop 了
onPause ->(A 被 B 覆蓋不可見(jiàn)后走)onStop ->(如果 A 自身 finish 或被系統(tǒng)回收后走)onDestory
//Activity B
onCreate -> onStart ->(B 會(huì)等到 A 的 onPause 執(zhí)行后走)onResume
- 3 從 Activity B 返回到 Activity A
//Activity B
onPause -> onStop -> onDestory
//Activity A
onRestart -> onStart -> onResume
//如果 Activity A 自身 finish 或被系統(tǒng)回收后,則這么走
onCreate(重新創(chuàng)建) -> onStart -> onResume
- 4 點(diǎn)擊 HOME 鍵、來(lái)電
//點(diǎn)擊 Home 鍵、來(lái)電
onPause -> onStop
//回到 App
onRestart -> onStart -> onResume
//如果被系統(tǒng)回收了,則這么走
onCreate(重新創(chuàng)建) -> onStart -> onResume
- 5 鎖屏與解鎖
//鎖屏
onPause -> onStop
//解鎖
onRestart -> onStart -> onResume
//如果被系統(tǒng)回收了,則這么走
onCreate(重新創(chuàng)建) -> onStart -> onResume
生命周期推薦做的事
onCreate
- 應(yīng)該盡量減少 onCreate 的工作量,避免程序啟動(dòng)太久而看不見(jiàn)界面,這里可以通過(guò) savedInstanceState 參數(shù)恢復(fù)一些狀態(tài),如果 Activity 是第一次創(chuàng)建的話此時(shí) savedInstanceState 為 null ,所以需要做判空處理
- 應(yīng)該調(diào)用 setContentView 方法初始化布局
- 定義成員變量(全局變量),初始化相關(guān)數(shù)據(jù)
- 初始化視圖控件等 UI 元素、配置 UI,將數(shù)據(jù)綁定到列表等
- 可能需要將 Activity 與 ViewModel 相關(guān)聯(lián)
- 可能需要啟動(dòng)與 Service 服務(wù)的綁定操作
onStart
- 注冊(cè) BroadcastReceiver 廣播接收器
- 地圖導(dǎo)航位置更新等相關(guān)的初始化
- 把在 onStop 中釋放的資源重新創(chuàng)建回來(lái)
onResume
- 意味著此時(shí) Activity 位于 Activity 堆棧的頂部,獲取了焦點(diǎn)
- 把 onPause 中暫停的操作恢復(fù)回來(lái),如 Camera 預(yù)覽
- 開(kāi)始動(dòng)畫(huà)、視頻的播放
- 可能需要注冊(cè)傳感器(如 GPS)監(jiān)聽(tīng)
onPause
- 不推薦在這里保存應(yīng)用或用戶數(shù)據(jù)、進(jìn)行網(wǎng)絡(luò)請(qǐng)求調(diào)用或執(zhí)行數(shù)據(jù)庫(kù)事務(wù)(可根據(jù)實(shí)際情況在 onPause 中保存一些非常重要的數(shù)據(jù)),即不適合做耗時(shí)較長(zhǎng)的工作,應(yīng)最大程度減少 onPause 的工作量避免 Activity 切換緩慢卡頓
- 釋放系統(tǒng)資源,傳感器(如 GPS)句柄、Camera 預(yù)覽等,通常是耗電的
- 停止動(dòng)畫(huà)、視頻的播放
- 地圖導(dǎo)航頁(yè)面一般不在這里釋放,因?yàn)橄M匀荒軌蚶^續(xù)工作
onStop
- 可以在這里保存應(yīng)用或用戶數(shù)據(jù)(比如將用戶編寫(xiě)的郵箱草稿保存到持久性存儲(chǔ)空間)、進(jìn)行網(wǎng)絡(luò)調(diào)用、用戶首選項(xiàng)持久性數(shù)據(jù)和執(zhí)行數(shù)據(jù)庫(kù)事務(wù)
- 應(yīng)該釋放那些不再需要的資源
- 關(guān)閉那些 CPU 執(zhí)行相對(duì)密集的操作
- 地圖導(dǎo)航可根據(jù)實(shí)際情況按需從精確位置更新切換到粗略位置更新
- 可以停止通過(guò) Service 定時(shí)更新 UI 上的數(shù)據(jù)的 Service
- 取消注冊(cè) BroadcastReceiver 廣播接收器
onDestoty
- 應(yīng)釋放先前的回調(diào)(如 onStop)中尚未釋放的所有資源
- 解除與 Service 服務(wù)的綁定
- 其實(shí)不推薦在 onDestroy 里執(zhí)行銷(xiāo)毀資源的工作,因?yàn)?onDestroy 執(zhí)行的時(shí)機(jī)可能較晚,可根據(jù)實(shí)際需求在
onPause 或 onStop 中結(jié)合 isFinishing 判斷來(lái)執(zhí)行
特殊情況下的生命周期
- 1 系統(tǒng)資源不足的情況下導(dǎo)致 Activity 被系統(tǒng)回收
- 2 系統(tǒng) Configuration 配置改變:橫豎屏切換、系統(tǒng)語(yǔ)言改變和切換到多窗口或分屏模式等
- 3 用戶強(qiáng)殺應(yīng)用或者使用系統(tǒng)【設(shè)置】里的【應(yīng)用管理器】來(lái)停止應(yīng)用以終止進(jìn)程
- 4 應(yīng)用程序出現(xiàn)異常崩潰
onSaveInstanceState
- 在 Activity 被系統(tǒng)銷(xiāo)毀并重新創(chuàng)建后調(diào)用,通常會(huì)在 onStop 之前調(diào)用
- Instance State 實(shí)例狀態(tài),是一個(gè)鍵值對(duì)集合存儲(chǔ)在 Bundle 對(duì)象中,保存著有關(guān) Activity 的 View Hierarchy State 視圖層次結(jié)構(gòu)狀態(tài)的瞬時(shí)信息(如輸入框的值、列表滑動(dòng)后停留的位置),系統(tǒng)用它來(lái)恢復(fù) Activity 先前的狀態(tài),默認(rèn)情況下系統(tǒng)使用 Bundle 對(duì)象中的實(shí)例狀態(tài)來(lái)保存 Activity 布局中每個(gè) View 對(duì)象的相關(guān)信息,系統(tǒng)因系統(tǒng)限制(例如 Configuration 配置變更或內(nèi)存壓力)等情況而銷(xiāo)毀 Activity 的場(chǎng)景,當(dāng)用戶嘗試回退到該 Activity 時(shí),系統(tǒng)會(huì)通過(guò)已保存的實(shí)例狀態(tài)去新建該 Activity 的實(shí)例,也就是整個(gè)過(guò)程 Activity 會(huì)先銷(xiāo)毀再重建,即無(wú)需編寫(xiě)代碼就能恢復(fù)布局狀態(tài)為其先前的狀態(tài),主動(dòng)調(diào)用 finish 方法和點(diǎn)擊返回鍵的場(chǎng)景是不會(huì)調(diào)用該方法保存狀態(tài)的
- super.onSaveInstanceState 里默認(rèn)已經(jīng)實(shí)現(xiàn)保存視圖層次結(jié)構(gòu)狀態(tài)的邏輯
- Bundle 對(duì)象并不適合保留大量數(shù)據(jù),在主線程中進(jìn)行序列化和反序列化,會(huì)產(chǎn)生一定內(nèi)存消耗,保存臨時(shí)數(shù)據(jù)為主,保存簡(jiǎn)單輕量的界面狀態(tài),如果保存大量數(shù)據(jù)應(yīng)該配合使用 ViewModel 進(jìn)行處理
onRestoreInstanceState
- 在 Activity 被系統(tǒng)銷(xiāo)毀并重新創(chuàng)建后調(diào)用,用于恢復(fù)之前保存的狀態(tài)數(shù)據(jù),通常在 onStart 或 onResume 之后調(diào)用
- 可用于恢復(fù)一些 onSaveInstanceState 方法中保存的數(shù)據(jù)
- super.onRestoreInstanceState 已經(jīng)實(shí)現(xiàn)恢復(fù)視圖層次結(jié)構(gòu)的狀態(tài)的邏輯
橫豎屏切換
- 如果是重建 Activity 的情況下,需要利用 onSaveInstanceState 和 onRestoreInstanceState 方法處理數(shù)據(jù)的保存與恢復(fù),來(lái)保證用戶數(shù)據(jù)或狀態(tài)不丟失
- 如果是不重建 Activity 情況下,那么我們可以按需利用 onConfigurationChanged 回調(diào)進(jìn)行判斷來(lái)展示橫豎屏不同界面的展示
//Android 3.2 API 13 以前
不設(shè)置 Activity 的 android:configChanges 時(shí),切屏?xí)匦抡{(diào)用各個(gè)生命周期,切橫屏?xí)r會(huì)執(zhí)行一次,切豎屏?xí)r會(huì)執(zhí)行兩次
設(shè)置了 Activity 的 android:configChanges="orientation" 時(shí),切屏還是會(huì)重新調(diào)用各個(gè)生命周期,切橫、豎屏?xí)r都只會(huì)執(zhí)行一次
設(shè)置了 Activity 的 android:configChanges="orientation|keyboardHidden" 時(shí),切屏不會(huì)重新調(diào)用各個(gè)生命周期,只會(huì)執(zhí)行 onConfigurationChanged 方法
//Android 3.2 API 13 及以后
不設(shè)置 Activity 的 android:configChanges 時(shí),或者設(shè)置了 Activity 的 android:configChanges="orientation" 時(shí),或者設(shè)置了 Activity 的android:configChanges="orientation|keyboardHidden" 時(shí),切屏?xí)匦抡{(diào)用各個(gè)生命周期,切橫屏?xí)r會(huì)執(zhí)行一次,切豎屏?xí)r會(huì)執(zhí)行一次
設(shè)置了 Activity 的 android:configChanges="orientation|screenSize|keyboardHidden",切屏不會(huì)重新調(diào)用各個(gè)生命周期,只會(huì)執(zhí)行 onConfigurationChanged 方法
常見(jiàn)問(wèn)題
1 如果在 onCreate 、onStart 和 onResume 等方法中直接調(diào)用 finish 方法,生命周期是怎樣的?
- 系統(tǒng)會(huì)跳過(guò)對(duì)應(yīng)的生命周期方法,可以簡(jiǎn)單理解 onCreate 和 onDestory ,onStart 和 onStop ,onResume 和 onPause 是對(duì)應(yīng)的,原理可以參見(jiàn)源碼里 Instrumentation 的判斷邏輯
//調(diào)用 finish 方法的時(shí)機(jī)
onCreate:onCreate -> onDestroy
onStart :onCreate -> onStart -> onStop -> onDestroy
onResume:onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy
2 什么時(shí)候只會(huì)走 onPause 方法,而不會(huì)走 onStop 方法?
- 打開(kāi)一個(gè)完全透明或是對(duì)話框主題的 Activity 的情況
3 Activity 在什么時(shí)候可能會(huì)出現(xiàn)不執(zhí)行 onDestory 方法的情況?
- 系統(tǒng)資源不足的情況下
- 用戶強(qiáng)殺應(yīng)用或者使用系統(tǒng)【設(shè)置】里的【應(yīng)用管理器】來(lái)停止應(yīng)用以終止進(jìn)程
- 應(yīng)用程序異常崩潰
- 切到多窗口或分屏模式
4 下拉狀態(tài)欄時(shí) Activity 的生命周期是什么?
- 不走任何生命周期,狀態(tài)欄和 AlertDialog、Toast 等都是通過(guò) WindowManager.addView 方法來(lái)顯示的,對(duì) Activity 的生命周期沒(méi)有影響,另外可以通過(guò) onWindowFocusChanged(boolean hasFocus) 來(lái)監(jiān)聽(tīng)狀態(tài)欄,hasFocus 為 false 可以表示下拉狀態(tài),從而可以實(shí)現(xiàn)暫停視頻等需求