Android的生命週期:onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDestroy() 以下圖所示:android
以下日誌打印 第一個activity MainActivity 打開 SingleTopActivity 在返回到 MainActivitygit
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。github
onStart()和onStop():onStart()表示activity可見了,可是尚未獲取焦點,沒法進行交互。onStop()是和onStart()對應的當activity從可見轉不可見是調用。app
onResume()和onPause():onResume()表示activity已經獲取焦點了,能夠進行交互了,onPause()是和onResume()方法對應的表示當前activity失去了焦點,此時能夠作一些存儲數據和中止動畫等工做,可是不能太好時,不是會影響到新的activity的顯示,由於只有onPause()執行完了,新的activity纔會進入 onCreate() 等方法。ide
onDestroy():onDestroy()表示activity正在銷燬,通常咱們是在這進行資源的釋放,以免內存的泄漏。動畫
注意:this
- 若是覆蓋在其上的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就可能被殺死。spa
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已經在棧頂並得到焦點了,而後咱們旋轉手機屏幕,3d
這時調用了 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按照優先級從高到低能夠分爲如下三種:
注意: 必須始終調用 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()方法中將每一個資源從新分配給每一個元素。
複製代碼
這個例子代碼在這裏