Activity 之生命週期

Activity 之生命週期

本文內容:
1. Activity 介紹
2. Activity 的生命週期
    2.1 生命週期圖
    2.2 常見情況下生命週期的回調
    2.3 關於生命週期常見問題
    2.4 異常狀態下活動的生命週期
        2.4.1 資源配置改變導致 Activity 重建
        2.4.2 低優先級 Activity 由於內存不足被殺死
    2.5 異常情況下的處理
        2.5.1 數據保存
        2.5.2 防止重建
3. 關於 Activity 的不常用的回調方法
    3.1 onPostCreate()
    3.2 onPostResume()
    3.3 onContentChanged()
    3.4 onUserInteraction()
    3.5 onUserLeaveHint()

1. Activity 介紹

  Activity 是 Android 的四大組件之一,主要用於提供窗口與用戶進行交互。

2. Activity 的生命週期

2.1 生命週期圖

  官網的 Activity 的生命週期圖:

  解釋圖中個方法的作用:

生命週期方法作用說明
onCreate 表示 Activity 正在被創建 activity 被創建時調用,一般在這個方法中進行活動的初始化工作,如設置佈局工作、加載數據、綁定控件等。
onRestart 表示 Activity 正在重新啓動 這個回調代表了 Activity 由完全不可見重新變爲可見的過程,當 Activity 經歷了 onStop() 回調變爲完全不可見後,如果用戶返回原 Activity,便會觸發該回調,並且緊接着會觸發 onStart() 來使活動重新可見。
onStart 表示 Activity 正在被啓動 經歷該回調後,Activity 由不可見變爲可見,但此時處於後臺可見,還不能和用戶進行交互。
onResume 表示 Activity 已經可見 已經可見的 Activity 從後臺來到前臺,可以和用戶進行交互。
onPause 表示 Activity 正在停止 當用戶啓動了新的 Activity ,原來的 Activity 不再處於前臺,也無法與用戶進行交互,並且緊接着就會調用 onStop() 方法,但如果用戶這時立刻按返回鍵回到原 Activity ,就會調用 onResume() 方法讓活動重新回到前臺。而且在官方文檔中給出了說明,不允許在 onPause() 方法中執行耗時操作,因爲這會影響到新 Activity 的啓動。
onStop 表示 Activity 即將停止 這個回調代表了 Activity 由可見變爲完全不可見,在這裏可以進行一些稍微重量級的操作。需要注意的是,處於 onPause() 和 onStop() 回調後的 Activity 優先級很低,當有優先級更高的應用需要內存時,該應用就會被殺死,那麼當再次返回原 Activity 的時候,會重新調用 Activity 的onCreate()方法。
onDestroy 表示 Activity 即將被銷燬 來到了這個回調,說明 Activity 即將被銷燬,應該將資源的回收和釋放工作在該方法中執行。

2.2 常見情況下生命週期的回調

(A 與 B 表示不同的 Activity )

情況回調
第一次啓動 onCreate() -> onStart() -> onResume()
從 A 跳轉到 B A_onPause() -> B_onCreate() -> B_onStart() -> B_onResume() -> A_onStop()
從 B 再次回到 A B_onPause() -> A_onRestart() -> A_onStart() -> A_onResume() -> B_onStop()
用戶按 home 鍵 onPause() -> onStop()
按 home 鍵後回到應用 onRestart() -> onStart() -> onResume()
用戶按電源鍵屏保 onPause() -> onStop()
用戶按電源鍵亮屏 onRestart() -> onStart() -> onResume()
用戶按 back 鍵回退 onPause() -> onStop() -> onDestroy()

  表中生命週期的驗證可以在 Activity關於生命週期一些問題的實踐驗證 文章中查看。

2.3 關於生命週期常見問題

問題回調
由活動 A 啓動活動 B時,活動 A 的 onPause() 與 活動 B 的 onResume() 哪一個先執行? 活動 A 的 onPause() 先執行,活動 B 的 onResume() 方法後執行
標準 Dialog 是否會對生命週期產生影響 沒有影響
全屏 Dialog 是否會對生命週期產生影響 沒有影響
主題爲 Dialog 的 Activity 是否會對生命週期產生影響 有影響,與跳轉 Activity 一樣

  關於生命週期的常見問題的驗證可以在 Activity關於生命週期一些問題的實踐驗證 文章中查看。

2.4 異常狀態下活動的生命週期

  當 Activity 在運行過程中發生一些情況時,生命週期流程也會發生變化。常見的異常情況有兩種,一種是資源配置改變;另一是內存不足導致生命週期流程發生變化。

2.4.1 資源配置改變導致 Activity 重建

  資源配置最常見的情況就是橫豎屏切換導致資源的變化,當程序啓動時,會根據不同的配置加載不同的資源,例如橫豎屏兩個狀態對應着兩張不同的資源圖片。如果在使用過程中屏幕突然旋轉,那麼 Activity 就會因爲系統配置發生改變而銷燬重建,加載合適的資源。

2.4.2 低優先級 Activity 由於內存不足被殺死

  後臺可以同時運行多個任務,當設備的內存空間不足時,系統爲了保證用戶的體驗,會按照進程優先級將一些低優先級的進程殺死以會回收內存資源,後臺 Activity 就有可能會被銷燬。

  系統回收進程的優先級:

(1) 前臺進程

  持有用戶正在交互的 Activty,即生命週期處於 onResume 狀態的活動。

  該進程有綁定到正在交互的 Activity 的 service 或前臺 service。

(2) 可見進程

  這種進程雖然不在前臺,但是仍然可見。

  該進程持有的 Activity 執行了 onPause 但未執行 onStop 。例如原活動啓動了一個 dialog 主題的 Activity,但此時原活動並非完全不可見。

  該進程有 service 綁定到可見的或前臺 Activity。

(3)服務進程

  進程中持有一個 service,同時不屬於上面兩種情況。

(4)後臺進程

  不屬於上面三種情況,但進程持有一個不可見的 Activity,即執行了 onStop 但未執行 onDestory 的狀態。

(5)空進程

  不包含任何活躍的應用組件,作用是加快下次啓動這個進程中組件所需要的時間,優先級低。

2.5 異常情況下的處理

  在發生異常情況後,用戶再次回到 Activity,原 Activity 會重新建立,原已有的數據就會丟失,比如用戶操作改變了一些屬性值,重建之後用戶就看不到之前操作的結果,在異常的情況下如何給用戶帶來好的體驗,有兩種辦法。

2.5.1 數據保存

  第一種就是系統提供的 onSaveInstanceState 和 onRestoreInstanceState 方法,onSaveInstanceState 方法會在 Activity 異常銷燬之前調用,用來保存需要保存的數據,onRestoreInstanceState 方法在 Activity 重建之後獲取保存的數據。

  在活動異常銷燬之前,系統會調用 onSaveInstanceState,可以在 Bundle 類型的參數中保存想要的信息,之後這個 Bundle 對象會作爲參數傳遞給 onRestoreInstanceState 和 onCreate 方法,這樣在重新創建時就可以獲取數據了。

  關於 onSaveInstanceState 與 onRestoreInstanceState 方法需要注意的一些問題:

  1. onSaveInstanceState 方法的調用時機是在 onStop 之前,與 onPause 沒有固定的時序關係。而 onRestoreInstanceState 方法則是在 onStart 之後調用。

  2. 正常情況下的活動銷燬並不會調用這兩個方法,只有當活動異常銷燬並且有機會重現展示的時候纔會進行調用,除了資源配置的改變外,activity 因內存不足被銷燬也是通過這兩個方法保存數據。

  3. 在 onRestoreInstanceState 和 onCreate 都可以進行數據恢復工作,但是根據官方文檔建議採用在 onRestoreInstanceState 中去恢復。

  4. 在 onSaveInstanceState 和 onRestoreInstanceState 這兩個方法中,系統會默認爲我們進行一定的恢復工作,具體地講,默認實現會爲佈局中的每個 View 調用相應的 onSaveInstanceState() 方法,讓每個視圖都能提供有關自身的應保存信息。Android 框架中幾乎每個小部件都會根據需要實現此方法,以便在重建 Activity 時自動保存和恢復付 UI 所做的任何可見更改。例如 EditText 中的文本信息、ListView 中的滾動位置等。也可以通過 android:saveEnabled 屬性設置爲 “false” 或通過調用 setSaveEnabled() 方法顯式阻止佈局內的視圖保存其狀態,通常不會將該屬性停用,除非想要以不同方式恢復 Activity IU 的狀態。

  5. onSveInstanceState() 常見的觸發場景有:橫豎屏切換、按下電源鍵、按下菜單鍵、切換到別的 Activity 等;onRestoreInstanceState() 常見的觸發場景有:橫豎屏切換、切換語言等等。

2.5.2 防止重建

  在默認情況下,資源配置改變會導致活動的重新創建,但是可以通過對活動的 android:configChanges 屬性的設置使活動防止重新被創建。

android:configChanges 屬性值

屬性值含義
mcc SIM 卡唯一標識IMSI(國際移動用戶標識碼)中的國家代碼,由三位數字組成,中國爲:460,這裏標識 mcc 代碼發生了變化
mnc SIM 卡唯一標識 IMSI(國際移動用戶標識碼)中的運營商代碼,有兩位數字組成,中國移動 TD 系統爲 00 ,中國聯通爲 01,電信爲 03,此項標識 mnc 發生了改變
locale 設備的本地位置發生了改變,一般指的是切換了系統語言
touchscreen 觸摸屏發生了改變
keyboard 鍵盤類型發生了改變,比如用戶使用了外接鍵盤
keyboardHidden 鍵盤的可訪問性發生了改變,比如用戶調出了鍵盤
navigation 系統導航方式發生了改變
screenLayout 屏幕布局發生了改變,很可能是用戶激活了另外一個顯示設備
fontScale 系統字體縮放比例發生了改變,比如用戶選擇了個新的字號
uiMode 用戶界面模式發生了改變,比如開啓夜間模式 -API8 新添加
orientation 屏幕方向發生改變,比如旋轉了手機屏幕
screenSize 當屏幕尺寸信息發生改變(當編譯選項中的 minSdkVersion 和 targeSdkVersion 均低於 13 時不會導致 Activity 重啓 ) API 13 新添加
smallestScreenSize 設備的物理尺寸發生改變,這個和屏幕方向沒關係,比如切換到外部顯示設備 -API13 新添加
layoutDirection 當佈局方向發生改變的時候,正常情況下無法修改佈局的 layoutDirection 的屬性 -API17 新添加

  可以在屬性中聲明多個配置值,方法使用 “|” 字符分割這些配置值。

  API 級別 13 或更高版本的應用時,若要避免由於設備方向改變(橫豎屏切換)而導致運行時重啓,則除了 “orientation” 值之外,還必須添加 “screenSize” 值。

  當其中一個配置發生變化時,Activity 不會重啓。相反,Activity 會收到對 onConfigurationChanged() 的調用。向此方法傳遞 Configuration 對象指定新設備配置。可以通過讀取 Configuration 中的字段,確定新配置,然後通過更新界面中使用的資源進行適當的更改。

  異常狀態下生命週期與異常情況下的處理的的驗證可以在 Activity關於生命週期一些問題的實踐驗證 文章中查看。

3 關於 Activity 的不常用的回調方法

3.1 onPostCreate()

  onPostCreate() 方法是指 onCreate() 方法徹底執行完畢的回調。一般我們都沒有實現這個方法,它的作用是在代碼開始運行之前,調用系統做最後的初始化工作。現在知道的做法是使用 ActionBarDrawerToggle 時在屏幕旋轉的時候在 onPostCreate() 中同步下狀態。

3.2 onPostResume()

  onPostResume() 與 onPostCreate() 方法類似,onPostResume() 方法在 onResume() 方法徹底執行完畢的回調。 onCreate() 方法中獲取某個 View 的高度和寬度時,返回的值是 0 ,因爲這個時候 View 可能還沒初始化好,但是在 onPostResume() 中獲取就不會有問題,因爲 onPostResume() 是在 onResume() 徹底執行完畢的回調。

3.3 onContentChanged()

  當 Activity 的佈局改動時,即 setContentView() 或者 addContentView() 方法執行完畢時就會調用該方法。所以,Activity 中 View 的 findViewById() 方法都可以放到該方法中。

3.4 onUserInteraction()

  Activity 無論分發按鍵事件、觸摸事件或者軌跡球事件都會調用 Activity#onUserInteraction()。如果想知道用戶用某種方式和你正在運行的 activity 交互,可以重寫 Activity#onUserInteraction()。所有調用 Activity#onUserLeaveHint() 的回調都會首先回調 Activity#onUserInteraction() 。

  Activity 在分發各種事件的時候會調用該方法,注意:啓動另一個 activity ,Activity#onUserInteraction()會被調用兩次,一次是 activity 捕獲到事件,另一次是調用 Activity#onUserLeaveHint() 之前會調用 Activity#onUserInteraction() 。

  可以用這個方法來監控用戶有沒有與當前的 Activity 進行交互。

3.5 onUserLeaveHint()

  當用戶的操作使一個 activity 準備進入後臺時,此方法會像 activity 的生命週期的一部分被調用。例如,當用戶按下 Home 鍵,Activity#onUserLeaveHint() 將會被調用。但是當來電導致 activity 自動佔據前臺(系統自動切換),Activity#onUserLeaveHint() 將不會被回調。

  一般監聽返回鍵,是重寫 onKeyDown() 方法,但是 Home 鍵和 Menu 鍵就不好監聽,但是可以在 onUserLeaveHint() 方法中監聽。

參考文章:

  1. 老生常談-Activity
  2. 全面瞭解 Activity
  3. 超詳細的生命週期圖-你能回答全嗎
  4. Android之Activity系列總結(一)—Activity概覽
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章