Android生命週期
Android的生命週期:onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDestroy() 如下圖所示:
- 1.當activity啟動時系統會先呼叫onCreate(),然後呼叫onStart(),最後呼叫**onResume()**方法,activity進入執行狀態。
- 當activity被別的activity 覆蓋在其上時:系統會掉用onPause(),然後當覆蓋在其上的activity會呼叫**onCreate() -> onStart() -> onResume()後,第一個activity會呼叫onStop()**方法使activity暫停。
- 當覆蓋在其上的第二個activity關閉返回此activity時,系統會先呼叫第二個activity的**onPause()方法然後再呼叫第一個activity的onRestart() -> onStart() -> onResume()方法,進入執行狀態,此時第二個activity才呼叫onStop() -> onDestroy()**方法關閉。
- 使用者退出當前activity:系統先呼叫onPause(),然後呼叫onSotp(),最後呼叫**onDestroy()**方法,結束當前activity。
如下日誌列印 第一個activity MainActivity 開啟 SingleTopActivity 在返回到 MainActivity
MainActivity :onPause 方法-------------------------
SingleTopActivity :onCreate 方法-------------------------
SingleTopActivity :onStart 方法-------------------------
SingleTopActivity :onResume 方法-------------------------
MainActivity :onSaveInstanceState 方法--------------------
MainActivity :onStop 方法-------------------------
SingleTopActivity :onPause 方法-------------------------
MainActivity :onRestart 方法-------------------------
MainActivity :onStart 方法-------------------------
MainActivity :onResume 方法-------------------------
SingleTopActivity :onStop 方法-------------------------
SingleTopActivity :onDestroy 方法-------------------------
複製程式碼
-
onRestart():表示activity正在重新啟動,一般情況下是當前activity從不可見重新變成可見狀態時,**onRestart()**就會被呼叫,這種情況一般是使用者行為導致的,如從其他頁面返回當前頁面時,或者使用者按home鍵切換到桌面在重新開啟app。
-
onStart()和onStop():onStart()表示activity可見了,但是還沒有獲取焦點,無法進行互動。onStop()是和onStart()對應的當activity從可見轉不可見是呼叫。
-
onResume()和onPause():onResume()表示activity已經獲取焦點了,可以進行互動了,onPause()是和onResume()方法對應的表示當前activity失去了焦點,此時可以做一些儲存資料和停止動畫等工作,但是不能太好時,不是會影響到新的activity的顯示,因為只有onPause()執行完了,新的activity才會進入 onCreate() 等方法。
-
onDestroy():onDestroy()表示activity正在銷燬,一般我們是在這進行資源的釋放,以避免記憶體的洩漏。
注意:
- 如果覆蓋在其上的activity的風格是dialog風格的化,此activity是不會進入**onSotp()**方法,回到此activity時也**不會呼叫onRestart()和onStart()方法** 會直接呼叫**onResume()**方法。
- 如果activity中彈出dialog對話方塊的時候,**activity是不會呼叫onPause()方法**;
- 只有舊的activity onPause()方法執行完後,新的activity才啟動
- 在所以情況下,系統在呼叫了onPause()和onStop()之後都會呼叫onDestroy(),只有一個例外:當你從onCreate()方法類呼叫了finish()時,在這種情況下,系統會立刻呼叫onDestroy(),而不呼叫任何其他生命週期方法。日誌如下:
複製程式碼
MainActivity :onPause 方法-------------------------
DialogActivity :onCreate 方法-------------------------
MainActivity :onResume 方法-------------------------
DialogActivity :onDestroy 方法-------------------------
複製程式碼
異常情況下的生命週期:比如系統資源配置發生改變以及系統記憶體不足時,activity就可能被殺死。
- 情況1:資源相關配置方式改變導致activity被殺死並重新建立。 比如當前activity處於豎屏,旋轉螢幕,這時由於activity的系統配置改為了橫屏狀態,在預設情況下,activity就會被銷燬並且重新建立,日誌列印如下:
MainActivity :onCreate 方法-------------------------
MainActivity :onCreate:MainActivity TaskId:130 hasCode:151566767
MainActivity :onStart 方法-------------------------
MainActivity :onResume 方法-------------------------
MainActivity :onPause 方法-------------------------
MainActivity :onSaveInstanceState 方法-------------------------
MainActivity :onStop 方法-------------------------
MainActivity :onDestroy 方法-------------------------
MainActivity :onCreate 方法-------------------------
MainActivity :onCreate:MainActivity TaskId:130 hasCode:233659052
MainActivity :onStart 方法-------------------------
MainActivity :onRestoreInstanceState 方法-------------------------
MainActivity :onResume 方法-------------------------
MainActivity :onPause 方法-------------------------
MainActivity :onSaveInstanceState 方法-------------------------
MainActivity :onStop 方法-------------------------
MainActivity :onDestroy 方法-------------------------
MainActivity :onCreate 方法-------------------------
MainActivity :onCreate:MainActivity TaskId:130 hasCode:262962597
MainActivity:TaskAffinity:com.hugo.reviewbasic
MainActivity :onStart 方法-------------------------
MainActivity :onRestoreInstanceState 方法-------------------------
MainActivity :onResume 方法-------------------------
複製程式碼
在上面這日誌中 我們進入MainActivity -> onCreate() -> onStart () -> onResume() 這個時候MainActivity已經在棧頂並獲得焦點了,然後我們旋轉手機螢幕,
這時呼叫了 onPause() -> onSaveInstanceState() -> onStop() - onDestroy() 方法把當前MainActivity 銷燬了,然後緊接著又重新建立了一個MainActivity -> onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()
這是MainActivity已經重新建立並且是橫屏顯示的,這是我們又旋轉手機螢幕重新豎屏顯示 ,這是呼叫了 onPause() -> onSaveInstanceState() -> onStop() - onDestroy() 方法把當前橫屏MainActivity 銷燬了,並重新建立了豎屏的MainActivity -> onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()
在這上面的流程我們可以看到 在第一次進入MainActivity 時是每有呼叫onRestoreInstanceState() 方法的而是在重新建立時才呼叫了該方法,這個方法是用來做什麼的呢?這個方法就是用來在activity被銷燬並重新建立時用來恢復我們儲存的資料用的,那我們的資料在哪儲存的呢,可以看到日誌裡每次在銷燬前都有呼叫 onSaveInstanceState() 方法,這個方法就是用來儲存資料用的。
在onSaveInstanceState()方法中系統會傳入Bundle物件用來儲存資料,在重新建立時onRestoreInstanceState()方法系統會傳入在onSaveInstanceState()方法是儲存了資料的Bundle物件,在onRestoreInstanceState()方法裡可以在傳入的Bundle物件中獲取儲存的資料進行頁面恢復。
根據日誌可以看出 onSaveInstanceState() 總是在 onStop()之前呼叫,而onRestoreInstanceState() 總是在onStart() 之後呼叫,而且onRestoreInstanceState()在activity第一次建立時是不會呼叫的。
-
情況2:在資源不足的情況下導致低優先順序的activity被殺死。 這種情況下和前面第一種情況1的資料儲存和恢復是完全一致的,activity按照優先順序從高到低可以分為以下三種:
- 前臺activity:正在和使用者互動的activity,優先順序最高。 2.可見但是非前臺activity:就是能看見,但是沒有獲取到焦點不能和使用者進行直接互動。 3.後臺activity:已經被暫停的activity,比如執行了onStop()方法,優先順序最低。
注意: 必須始終呼叫 onSaveInstanceState()和onRestoreInstanceState() 的超類實現因為這兩個方法預設實現了儲存有關activity檢視層次的狀態資訊和恢復檢視層次結構狀態,列如EditText小部件的文字或ListView的滾動位置。而且所有的View都有onSaveInstanceState()和onRestoreInstanceState()這兩個方法。
自行處理配置變更: 我們可以在宣告Activity將自行處理配置變更,這樣就可以阻止系統重啟activity了。 宣告時在AndroidManifest.xml檔案中編輯相應的""元素,設定以包含的 android:configChanges 屬性(最常用的值包括“orientation”和“keyboardHidden”,分別用於避免因螢幕方向和可用鍵盤改變而導致的重啟)。我們可以在該屬性中宣告多個匹配值,方法是用“ | ”字元分隔這些配置值。 如下配置:
<activity android:name=".singletop.OtherTopActiivty"
android:configChanges="orientation|screenSize"
android:launchMode="singleTop"/>
複製程式碼
現在,當其中一個配置發生改變是OtherTopActiivty不會重啟,但是OtherTopActiivty的onConfigurationChanged()方法會被呼叫,系統會 傳入Configuration物件指定新的裝置配置。我們可以通過讀Configuration中的欄位,來確定新配置,進行相應的UI更改。 以下是在onConfigurationChanged()實現檢查當前裝置的方向:
override fun onConfigurationChanged(newConfig: Configuration?) {
super.onConfigurationChanged(newConfig)
LogUtil.i(TAG,"$ActivityName :onConfigurationChanged 方法-------------------------")
if(newConfig?.orientation == Configuration.ORIENTATION_LANDSCAPE){
LogUtil.i(TAG,"$ActivityName :onConfigurationChanged 橫屏")
Toast.makeText(this,"橫屏",Toast.LENGTH_SHORT).show()
}else if(newConfig?.orientation == Configuration.ORIENTATION_PORTRAIT){
LogUtil.i(TAG,"$ActivityName :onConfigurationChanged 豎屏")
Toast.makeText(this,"豎屏",Toast.LENGTH_SHORT).show()
}
}
複製程式碼
注意:
-
自行處理配置變更可能導致備用資源的使用更為困難,因為系統不會自動應用這些資源。所以只有在我們必須避免activity因配置改變而重啟這種情況下,才考慮採用自行處理配置變更這種方法,而且對於大多數應用並不建議使用此方法。 複製程式碼
-
在Android3.0(API 級別13)開始,裝置在縱向和橫向之間切換時,“螢幕尺寸”也會發生改變,因此在開發針對API級別13或更高版本的應用時,若要避免由於裝置方向的改變而導致執行時重啟,則除了“orientation”值外,還必須新增“screenSize“值。也就是必須宣告android:configChanges="orientation|screenSize"。 複製程式碼
-
在宣告有Activity處理配置變更時,我們有責任要為其提供備用資源的所有元素。如宣告瞭activity處理方向變更,有些影象是應該橫向和縱向之間切換,則必須在 onConfigurationChanged()方法中將每個資源重新分配給每個元素。 複製程式碼
這個例子程式碼在這裡