Android中元件生命週期完全解析

weixin_34249678發表於2018-05-07

一說到Android生命週期大家可能都會想到一個特別經典的圖:
補圖
看完可能大家都會似懂非懂知道什麼叫做生命週期。但其實看完這個生命週期其實也只是瞭解Android中的“主要”生命週期部分。因為Android的生命週期並不僅僅包含這些。接下來想跟大家分享的是Android中生命週期一般處理方法是什麼樣的。

說到生命週期,主要有兩大元件有生命週期--Activity,Fragment。之前還會有Dialog,但之後DialogFragment取代,而DialogFragment又是Fragment的子類。所以下面我們討論的就是Activity和Fragment的生命週期。

生命週期控制器?要談生命週期就不得不討論一下生命週期是如何實現的。
Fragment的控制器我覺得大家都特別的熟悉,就是FragmentManager,FragmentManager類其實是一個抽象類,相關的實現方法都在FragmentManagerImpl中實現的。其中狀態之間的切換都放在一個方法叫moveToState()方法中,有興趣的同學可以研究下。大體邏輯我在這邊說一下,分為兩種情況:

  1. 現在的狀態先於原Fragment狀態
  2. 現在的狀態晚於原Fragment狀態
    什麼意思呢?什麼叫先於,什麼叫晚於呢??
    我們可以知道Fragment其實就是一個狀態機,而他的狀態的表現方法其實是Int的列舉型別。不同的狀態分別由不同的Int值所代替。如果現在要改變的狀態的值要變大,就說明現在的狀態晚於原Fragment狀態,如果小的話就是現在的狀態先於原Fragment狀態。
    補圖(程式碼縮圖)
    接下來是moveToState()簡單的流程圖,便於大家的理解。
    補圖

既然Fragment都有生命週期控制器了,Activity沒有豈不是很說不過去?所以某天我找了一下Activity的生命週期控制器,這個類的名字叫ActivityThread。他跟Fragment的實現方式不太一樣。Activity的生命週期比Fragment的相對複雜一些。ActivityThread主要控制一些Activity的主要邏輯,比如啟動Activity,重新啟動Activity,停止Activity等。
補圖
而這個控制器ActivityThread並不是直接控制Activity的,還封裝了一層Instrumentation類,控制Activity的各個階段需要做的事情。
補圖

看完了相互之間獨立的生命週期之後,我們需要了解一下Fragment與Activity之間的聯動了。當Fragment依附於Activity之中的View時,Activity和Fragment的生命週期是怎樣的?

首先得說一下既然Fragment依附於Activity。就說明Activity是控制Fragment的生命週期的。那通過什麼控制呢?可以找到是通過FragmentController來控制FragmentManager進而控制Fragment生命週期的。相關我就不進行程式碼研讀了,簡單畫一下Fragment與Activity互動的流程圖吧
補圖

最後我們看完了所有Android的生命週期的二三事,來解決一個Bug吧。
補Bug
初看這個Bug覺得會有一些不可思議,因為這是一個“偶現”Bug並不是所有進入這個Fragment的使用者都會有空指標崩潰,但是理論上來說並不應該出現這樣的空指標。但是為什麼會出現呢?
我們來分析一下,空指標就是因為沒有初始化,但是進入Fragment的時候肯定會初始化,為什麼會沒有初始化呢?只有一種可能性!!就是Activity在後臺的時候被系統回收掉了。這樣的問題常常會發生在APP之間相互跳轉,比如分享、第三方支付等場景。進而內部變數都會變成null,如果呼叫的話肯定會爆空指標崩潰!
如何復現呢?這樣的問題還是比較普遍的,總不能每次線上有問題了,才去解決吧。
在開發者選項中,有一個不保留使用者活動,當勾時,每次進入下一個Activity的時候就會把上一個Activity銷燬,返回上一個Activity時會重新建立。
知道了如何復現,就可以改Bug了。我們再來看下Activity的生命週期:
補圖
當頁面銷燬的時候會進入onPause()、onStop()、onDestroy(),其實還有一個生命週期也會進入,就是onSaveInstanceState(Bundle outState)。重新建立的時候會走onRestoreInstanceState(Bundle savedInstanceState)所以我們只要搞清楚頁面需求,將必要頁面資料儲存在onSaveInstanceState方法中,onRestoreInstanceState重新恢復就好。

附一個Demo

相關文章