一、概述
學習Activity生命周期,首先我們要明白,學習它的目的不僅在于要知道有哪些生命周期,而是在于明白各回掉函數(shù)調用的時機,以便在合適的時機進行正確的操作,如初始化變量、頁面展示、數(shù)據(jù)操作、資源回收等。平時的工作習慣都是,onCreate(xxx)初始化,onResume()注冊、拉取數(shù)據(jù),onPause()反注冊,onDestroy()釋放資源,這篇文章總結了一些和關鍵生命周期相關聯(lián)的一些要點。
二、金字塔模型

Activity 生命周期金字塔模型.png
在官方文檔中,把
Activity的生命周期理解成為一個金字塔模型,它是基于下面兩點:
- 金字塔的每個階梯表示
Activity所處的狀態(tài) - 各回調函數(shù)則是各狀態(tài)轉換過程當中所經(jīng)過的路徑
這個模型中包含了Activity的六種狀態(tài):
-
Created:創(chuàng)建完成 -
Started:可見 -
Resumed:可見 -
Paused:部分可見 -
Stopped:不可見 -
Destroyed:銷毀
在這六種狀態(tài)當中,只有Resumed、Paused、Stopped這幾種狀態(tài)在用戶沒有進一步操作時會保持在該狀態(tài),而其余的,都會在執(zhí)行完相應的回調函數(shù)后快速跳過。
三、關鍵生命周期
3.1 protected void onCreate(Bundle savedInstanceState)
- 該方法被回調時,意味著一個新的
Activity被創(chuàng)建了。 - 由于當前處于一個新的
Activity實體對象當中,所有的東西都是未初始化的,我們一般需要做的事情包括調用setContentView方法設置該Activity的布局,初始化類成員變量。 -
onCreate(xxx)方法執(zhí)行完之后,Activity就進入了Created狀態(tài),然而它并不會在這個狀態(tài)停留,系統(tǒng)會接著回調onStart()方法由Created狀態(tài)進入到Started狀態(tài)。 - 注意到,
onCreate(xxxx)是所有這些回調方法中唯一有參的,該參數(shù)保存了上次由于Activity被動回收時所保存的數(shù)據(jù)。
3.2 protected void onStart()
-
onStart()方法執(zhí)行完后,Activity就進入了Started狀態(tài),它也同樣不會在該狀態(tài)停留,而是接著回調onResume()方法進入Resumed狀態(tài)。 -
onStart()被回調的情況有兩種: - 從
Created狀態(tài)過來 - 從
Stopped狀態(tài)過來,從這種狀態(tài)過來還會先經(jīng)過onRestart()方法。 - 由于它也會從
Stopped狀態(tài)跳轉過來,因此如果我們在onStop()當中反注冊了一些廣播,或者釋放了一些資源,那么在這里需要重新注冊或者初始化,可以認為,onStart()和onStop()是成對的關系。 -
Created和Started都不是持久性的狀態(tài),那么為什么要提供一個onStart()回調給開發(fā)者呢,直接由Created狀態(tài)或者是Stopped狀態(tài)經(jīng)過onResume()這條路走到Resumed狀態(tài)不就可以嗎,那么我們就要分析一下從onCreate()到onStart(),再到onResume()的過程中,做了哪些其它的操作,這有利于我們在平時的開發(fā)中區(qū)分這兩個回調的使用場景,我們來看一下源碼。
首先我們看一下onStart()方法調用的地方,通過下面這段代碼,我們可以知道Activity的onStart()最初是通過Activity#performStart()方法調用過來的:
<!-- Activity.java -->
private Instrumentaion mInstrumentation;
final void performStart() {
mInstrumentation.callActivityOnStart(this);
}
<!-- Instrumentaion.java -->
public void callActivityOnStart(Activity activity) {
activity.onStart();
}
而Activity#performStart()方法是由ActivityThread#performLaunchActivity(調過來的:
<!-- ActivityThread.java -->
private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity a = performLaunchActivity(r, customIntent); //performCreate, performStart()
if (a != null) {
....
handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed); //performResume()
....
}
}
//首先看一下調用performCreate, performStart的地方。
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
mInstrumentation.callActivityOnCreate(activity, r.state); //performCreate
....
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); //1.onRestoreIntanceState()
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
mInstrumentation.callActivityOnPostCreate(activity, r.state); //2.onPostCreate
if (!activity.mCalled) {
throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPostCreate()");
}
}
...
}
//這是performResume的入口。
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
ActivityClientRecord r = performResumeActivity(token, clearHide);
}
//最后看一下performResume真正執(zhí)行的地方。
public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide) {
try {
if (r.pendingIntents != null) {
deliverNewIntents(r, r.pendingIntents); //3.onNewIntent()
r.pendingIntents = null;
}
if (r.pendingResults != null) {
deliverResults(r, r.pendingResults); //4.onActivityResult()
r.pendingResults = null;
}
r.activity.performResume();
}
- 通過上面這段代碼,我們可以得出以下幾點啟發(fā):
-
onStart()到onResume()的過程中,還可能會回調onRestoreInstanceState/onPostCreate/onNewIntent/onActvitiyResult這幾個方法。 - 如果應用退到后臺,再次被啟動(
onNewIntent),或者通過startActivityForResult方法啟動另一個Activity得到結果返回(onActivityResult)的時候,在onStart()方法當中得到的并不是這兩個回調的最新結果,因為上面的這兩個方法并沒有調用,而在onResume()當中,這點是可以得到保證的。
3.3 protected void onResume()
- 該方法被回調時,意味著
Activity已經(jīng)完全可見了,但這個完全可見的概念并不等同于Activity所屬的Window被Attach了,因為在Activity初次啟動的時候,Attach的操作是在回調onResume()之后的,也就是下面的這段代碼
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
....
ActivityClientRecord r = performResumeActivity(token, clearHide);
....
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
WindowManager.LayoutParams l = r.window.getAttributes();
...
wm.addView(decor, l);
}
}
- 在
onResume()方法被回調時,由于DecorView并不一定Attach了,因此這時候我們獲取布局內某些View的寬高得到的值有可能是不正確的,既然onResume()當中不能保證,那么onStart()方法也是同理,所有需要在attachToWindow之后才能執(zhí)行或是期望得到正確結果的操作都需要注意這一點。 - 在
onResume當中,我們一般會做這么一些事:在可見時重新拉取一些需要及時刷新的數(shù)據(jù)、注冊ContentProvider的監(jiān)聽,最重要的是在onPause()中的一些釋放操作要在這里面恢復回來。
3.4 protected void onPause()
- 該方法被回調時,意味著
Activity部分不可見,例如一個半透明的界面覆蓋在了上面,這時候只要Activity仍然有一部分可見,那么它會一直保持在Paused狀態(tài)。 - 如果用戶從
Paused狀態(tài)回到Resumed狀態(tài),只會回調onResume方法。 - 在
onPause()方法中,應該暫停正在進行的頁面操作,例如正在播放的視頻,或者釋放相機這些多媒體資源。 - 在
onPause()當中,可以保存一些必要數(shù)據(jù)到持久化的存儲,例如正在編寫的信息草稿。 - 不應該在這里執(zhí)行耗時的操作,因為新界面啟動的時候會先回調當前頁面的
onPause()方法,所以如果進行了耗時的操作,那么會影響到新界面的啟動時間,官方文檔的建議是這些操作應該放到onStop()當中去做,其實在onStop()中也不應當做耗時的操作,因為它也是在主線程當中的,而在主線程中永遠不應該進行耗時的操作。 - 釋放系統(tǒng)資源,例如先前注冊的廣播、使用的傳感器(如
GPS)、以及一些僅當頁面獲得焦點時才需要的資源。 - 當處于
Paused狀態(tài)時,Activity的實例是被保存在內存中的,因此在其重新回到Resumed狀態(tài)的過程中,不需要重新初始化任何的組件。
3.5 protected void onStop()
- 該方法被回調時,表明
Activity已經(jīng)完全不可見了。 - 在任何場景下,系統(tǒng)都會先回調
onPause(),之后再回調onStop()。 - 官方文檔有談到,當
onStop()執(zhí)行完之后,系統(tǒng)有可能會銷毀這個Activity實例,在某些極端情況下,有可能不會回調onDestroy()方法,因此,我們需要在onStop()當中釋放掉一些資源來避免內存泄漏,而onDestory()中需要釋放的是和Activity相關的資源,如線程之類的(這點平時在工作中很少用,一般我們都是在onDestroy()中釋放所有資源,而且也沒有去實現(xiàn)onStart()方法,究竟什么時候不會走onDestroy(),這點值得研究,目前的猜測是該Activity在別的地方被引用了,導致其不能回收)。 - 當
Activity從Stopped狀態(tài)回到前臺時,會先回調onRestart()方法,然而我們更多的是使用onStart()方法作為onStop()的對應關系,因為無論是從Stopped狀態(tài),還是從Created狀態(tài)跳轉到Resumed狀態(tài),都是需要初始化必要的資源的,而它們經(jīng)過的共同路徑是onStart()。
3.6 protected void onDestroy()
- 該方法被回調時,表明
Activity是真正要被銷毀了, - 此時應當釋放掉所有用到的資源,避免內存泄漏。