喜聞樂見之Activity生命週期

Activity的生命週期,對於Android開發者來講,再熟悉不過了。可是咱們接觸到的資料,絕大部分都只是談了一些表面上的東西,例如各個回調的順序等等。本文試圖換個角度來說解,也但願對各位讀者有所幫助。html

生命週期

首先附上一張你們都熟悉的不能再熟悉的圖了android

Android生命週期

對於各個流程的回調,想必你們早已熟記於心了,對於單個Activity來講,徹底沒問題,複雜點的,不就是轉屏嘛?能有啥,好的,下面幾個問題,麻煩你們先思考下。ios

  1. FirstActivity啓動了SecondActivity,整個流程是怎樣的?
  2. setContentView若是放在onStart或者onResume中,會有什麼問題嗎?
  3. onPause中能夠保存狀態,爲何還要onSaveInstanceState,onCreate中有恢復機制,爲何還須要onRestoreInstanceState?
  4. 如何判斷一個Activity真正可見

來自官方

在回答這些問題以前,先來回顧下Activity的各個階段,下面的英文部分出自Google Android官方文檔app

onCreate

Called when the activity is first created. This is where you should do all of your normal static set up: create views, bind data to lists, etc. This method also provides you with a Bundle containing the activity's previously frozen state, if there was one. Always followed by onStart().ide

直接看重點,onCreate是用來幹啥的,建立view、綁定data的地方。是初始化Activity的地方,setContentView以及獲取控件都應該放在這裏去作。動畫

onStart

Called when the activity is becoming visible to the user. Followed by onResume() if the activity comes to the foreground, or onStop() if it becomes hidden.ui

onPause會被調用,是在Activity正在對用戶變得可見的時候。也就是說這個時候,對於用戶來講不是真正的可見,也不可去響應用戶的輸入。this

onResume

Called when the activity will start interacting with the user. At this point your activity is at the top of the activity stack, with user input going to it. Always followed by onPause().spa

onResume是在將要能夠產生交互的時候被調用的,也就是說,還不能響應用戶的輸入操做。在這個階段,Activity已是處在棧頂了。設計

onPause

Called when the system is about to start resuming a previous activity. This is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, etc. Implementations of this method must be very quick because the next activity will not be resumed until this method returns. Followed by either onResume() if the activity returns back to the front, or onStop() if it becomes invisible to the user.

onPause能夠用來幹啥,中止動畫或者那些佔用CPU操做的地方,可是在onPause裏面進行的操做,不可以過久,應該very quick,由於下一個Activity須要等onPause結束後纔會被調起。這個very quick的時間,應該是多少了?這個在ActivityManagerService中有定義,不能超過500ms。若是在onPause裏面處理時間超過5秒的話,會不會出現ANR呢?

// How long we wait until giving up on the last activity to pause.  This
// is short because it directly impacts the responsiveness of starting the
// next activity.
static final int PAUSE_TIMEOUT = 500;
複製代碼

onStop

Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one. This may happen either because a new activity is being started, an existing one is being brought in front of this one, or this one is being destroyed. Followed by either onRestart() if this activity is coming back to interact with the user, or onDestroy() if this activity is going away.

onStop的描述很簡單,Activity對用戶不可見時調用,可是文檔後面Killable一欄顯示的是YES,也就是說,onStop有可能會被強制結束掉而不完整的執行。

onDestroy

The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.

onDestroy是在Activity要被釋放掉時調用的,可是這個被釋放,有主動的(手動去調用finish())和被動的(系統回收),能夠經過isFinishing來區分這兩種場景。

onSaveInstanceState

This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state.

The default implementation takes care of most of the UI per-instance state for you by calling onSaveInstanceState() on each view in the hierarchy that has an id, and by saving the id of the currently focused view (all of which is restored by the default implementation of onRestoreInstanceState(Bundle)).

If called, this method will occur after onStop() for applications targeting platforms starting with P. For applications targeting earlier platform versions this method will occur before onStop() and there are no guarantees about whether it will occur before or after onPause().

從官網的三段介紹,能夠看出幾點

首先,onSaveInstanceState的調用時機,它是在當前Activity可能會被殺死的時候纔會觸發,什麼場景下會被殺死呢?當前Activity存在被回收的可能,就可能會被系統殺死。若是用戶主動的去殺死當前Activity,這個方法是不會被調用的。

其次,它的做用主要是用於存儲UI層面的狀態,不一樣於onPause。

最後,這個方法的調用時機,在不一樣的系統中不一樣,從Android P開始,它是在onStop以後調用的,在以前的系統中,則是在onStop以前調用的。可是是否發生在onPause先後,則看具體狀況。

onRestoreInstanceState

This method is called after onStart() when the activity is being re-initialized from a previously saved state, given here in savedInstanceState. Most implementations will simply use onCreate(Bundle) to restore their state, but it is sometimes convenient to do it here after all of the initialization has been done or to allow subclasses to decide whether to use your default implementation. The default implementation of this method performs a restore of any view state that had previously been frozen by onSaveInstanceState(Bundle).

This method is called between onStart() and onPostCreate(Bundle).

能夠看出,這個方法的主要做用,是恢復在onSaveInstanceState中保存的狀態。它的調用時機在onStart和onPostCreate之間。

回到問題

讀了谷歌官方文檔,是否會發現一些平時開發中沒有注意到的點呢?接下來咱們回到上面的幾個問題。

FirstActivity啓動了SecondActivity,整個流程是怎樣的?

在正常狀況下,按照文檔說的,首先會去調用FirstActivity的onPause方法,在onPause方法結束完畢後,而後調用SecondActivity的onCreate、onStart、onResume,最後是FirstActivity的onStop。這個是根據文檔來推斷的,咱們實際跑一下程序。

I/FirstActivity: =====FirstActivity=====onPause
I/FirstActivity: =====FirstActivity=====onWindowFocusChanged
I/SecondActivity: =====SecondActivity=====onCreate
I/SecondActivity: =====SecondActivity=====onStart
I/SecondActivity: =====SecondActivity=====onResume
I/SecondActivity: =====SecondActivity=====onWindowFocusChanged
複製代碼

從打印的log能夠看出,跟推斷的同樣,首先調用的是FirstActivity的onPause,而後纔是resume SecondActivity。

setContentView若是放在onStart或者onResume中,會有什麼問題嗎?

從官方文檔來看,也只是說應該把setContentView放在onCreate中,並無說必須放在這裏,因此應該也不會有顯示以及調用的問題吧。仍是跑一下程序看看,分別將setContentView以及設置點擊事件放在onStart以及onResume中,跑了下程序,沒有出現顯示問題。可是這個僅僅是顯示上的問題,會不會存在效率的問題呢?咱們來打印一下時間,以調用onCreate到onWindowFocusChanged之間的時間,做爲Activity加載時間,來進行對比

I/SecondActivity: =====SecondActivity=====Load Time:56
I/SecondActivity: =====SecondActivity=====Load Time:57
I/SecondActivity: =====SecondActivity=====Load Time:57
複製代碼

三次時間幾乎同樣的,也就是說,若是隻是單叢初次啓動的效率來講,在三個地方去進行setContentView是沒有任何差異的。可是爲甚麼官方說應該放在onCreate裏面去處理了,這是由於,onCreate在正常情況下,只會被調用一次,而onStart以及onResume都會被調用屢次,放在這裏面去作的話,在onResume的過程,會增長額外的耗時。

另外,因爲onRestoreInstanceState是在onStart以後才調用的,若是將setContentView放在onResume的話,可能會產生問題。

onPause中能夠保存狀態,爲何還要onSaveInstanceState,onCreate中有恢復機制,爲何還須要onRestoreInstanceState?

首先,onSaveInstanceState以及onRestoreInstanceState是Android進行UI狀態保存與恢復的一套單獨的機制。說是單獨的機制,是由於每一個view裏面,都會有onSaveInstanceState去進行一些默認的狀態保存操做,常規狀態下不須要用戶去幹預,比方說編輯框中輸入的文本信息,這樣作爲開發者省了不少事。

根據官方文檔來看,onPause主要的做用是中止動畫以及一些耗CPU的操做,能夠用於保存狀態。onSaveInstanceState主要做用是對UI進行狀態保存。二者的側重點不一樣,onPause也能夠保存UI的狀態,可是,onPause設計的主要目的是和onStart配對,中止耗時操做。

onCreate中也能夠恢復狀態,可是onRestoreInstanceState的觸發時間滯後於onCreate,在onStart以後執行,它設計的目的是用來恢復onSaveInstanceState中保存的狀態。

onPause以及onCreate能夠幹這些事情,可是它們當初不是設計出來,專門幹這個事情的。

如何判斷一個Activity真正可見?

對於這個問題,其實沒有嚴格的說法,onResume以及onWindowFocusChanged中均可以作判斷,可是官方文檔上說,onWindowFocusChanged是Activity對用戶是否可見最好的指示器。

擴展以外

好了,上面幾個問題都回答了,谷歌官方文檔寫的很是的詳細。那麼,問題又來了

谷歌爲何要設計生命週期中的這幾種狀態呢?

從谷歌的官方文檔能夠看出,onStart,是經過是否可見這種狀態來做爲區分,onResume則是經過是否能夠交互來區分,onPause設計的是與onResume相對應,onStop與onStart相對應,onCreate則是與onDestroy對應。

能夠看出,谷歌在設計Activity的生命週期時,主要的依據是,是否可見以及是否可交互。那麼這兩種狀態對於Activity來講有哪些影響呢?

仔細想一想,不難看出,在正常情況下,Activity的生命週期也是根據這兩個因素來運做的。失去焦點時,流程會走向onPause,獲取焦點,則會走向onResume。徹底不可見時,會走向onStop,後面又可見時,會去調取onStart。正常情況下的狀態變換,都是圍繞着這兩個因素來流動的。

onCreate中作動畫失效、設置屬性失敗的緣由?

這個問題,我想stackoverflow上有很是多的解決方案,可是從根本上去說,是由於onCreate的時候,元素還不可見,因此作不了動畫,一些控件沒法去設置屬性。

onPause中處理時間過長,是否會引發問題呢?

若是時間過長,會引起ANR。若是時間大於限定值500ms,會出現 pause timeout 的警告。

最後的話

本文只是單純的從Activity生命週期的角度,來分析一些問題,並對一些現狀作了解釋。固然,我所表述的有可能會有問題,歡迎你們指正。

平時接觸到的書籍以及網上的資料,包括平常的開發中,這些問題的分析解答少之又少。這些問題也一直困擾着我,所以我才寫了這篇文章,就最多見的東西,換個角度去看問題。我所參考的資料簡單的不能再簡單了,就是谷歌文檔,一些結論也是依據文檔中的描述所推導的。

最後感謝你們的閱讀。

我的博客

相關文章
相關標籤/搜索