Activity 知識(shí)梳理(1) - Activity生命周期

一珊膜、概述

學(xué)習(xí)Activity生命周期卷玉,首先我們要明白,學(xué)習(xí)它的目的不僅在于要知道有哪些生命周期庶喜,而是在于明白各回掉函數(shù)調(diào)用的時(shí)機(jī)小腊,以便在合適的時(shí)機(jī)進(jìn)行正確的操作,如初始化變量久窟、頁面展示秩冈、數(shù)據(jù)操作、資源回收等斥扛。平時(shí)的工作習(xí)慣都是入问,onCreate(xxx)初始化,onResume()注冊(cè)稀颁、拉取數(shù)據(jù)芬失,onPause()反注冊(cè),onDestroy()釋放資源匾灶,這篇文章總結(jié)了一些和關(guān)鍵生命周期相關(guān)聯(lián)的一些要點(diǎn)棱烂。

二、金字塔模型

Activity 生命周期金字塔模型.png

在官方文檔中阶女,把Activity的生命周期理解成為一個(gè)金字塔模型颊糜,它是基于下面兩點(diǎn):

  • 金字塔的每個(gè)階梯表示Activity所處的狀態(tài)
  • 回調(diào)函數(shù)則是各狀態(tài)轉(zhuǎn)換過程當(dāng)中所經(jīng)過的路徑

這個(gè)模型中包含了Activity的六種狀態(tài):

  • Created:創(chuàng)建完成
  • Started:可見
  • Resumed:可見
  • Paused:部分可見
  • Stopped:不可見
  • Destroyed:銷毀

在這六種狀態(tài)當(dāng)中,只有Resumed秃踩、Paused衬鱼、Stopped這幾種狀態(tài)在用戶沒有進(jìn)一步操作時(shí)會(huì)保持在該狀態(tài),而其余的憔杨,都會(huì)在執(zhí)行完相應(yīng)的回調(diào)函數(shù)后快速跳過鸟赫。

三、關(guān)鍵生命周期

3.1 protected void onCreate(Bundle savedInstanceState)

  • 該方法被回調(diào)時(shí),意味著一個(gè)新的Activity被創(chuàng)建了抛蚤。
  • 由于當(dāng)前處于一個(gè)新的Activity實(shí)體對(duì)象當(dāng)中台谢,所有的東西都是未初始化的,我們一般需要做的事情包括調(diào)用setContentView方法設(shè)置該Activity的布局霉颠,初始化類成員變量对碌。
  • onCreate(xxx)方法執(zhí)行完之后,Activity就進(jìn)入了Created狀態(tài)蒿偎,然而它并不會(huì)在這個(gè)狀態(tài)停留,系統(tǒng)會(huì)接著回調(diào)onStart() 方法由Created狀態(tài)進(jìn)入到Started狀態(tài)怀读。
  • 注意到诉位,onCreate(xxxx)是所有這些回調(diào)方法中唯一有參的,該參數(shù)保存了上次由于Activity被動(dòng)回收時(shí)所保存的數(shù)據(jù)菜枷。

3.2 protected void onStart()

  • onStart()方法執(zhí)行完后苍糠,Activity就進(jìn)入了Started狀態(tài),它也同樣不會(huì)在該狀態(tài)停留啤誊,而是接著回調(diào) onResume()方法進(jìn)入Resumed狀態(tài)岳瞭。
  • onStart()被回調(diào)的情況有兩種:
  • Created狀態(tài)過來
  • Stopped狀態(tài)過來,從這種狀態(tài)過來還會(huì)先經(jīng)過onRestart()方法蚊锹。
  • 由于它也會(huì)從Stopped狀態(tài)跳轉(zhuǎn)過來瞳筏,因此如果我們?cè)?code>onStop()當(dāng)中反注冊(cè)了一些廣播,或者釋放了一些資源牡昆,那么在這里需要重新注冊(cè)或者初始化姚炕,可以認(rèn)為,onStart()onStop()是成對(duì)的關(guān)系丢烘。
  • CreatedStarted都不是持久性的狀態(tài)柱宦,那么為什么要提供一個(gè)onStart()回調(diào)給開發(fā)者呢,直接由Created狀態(tài)或者是 Stopped狀態(tài)經(jīng)過onResume()這條路走到Resumed狀態(tài)不就可以嗎播瞳,那么我們就要分析一下從 onCreate()onStart()掸刊,再到onResume()的過程中,做了哪些其它的操作赢乓,這有利于我們?cè)谄綍r(shí)的開發(fā)中區(qū)分這兩個(gè)回調(diào)的使用場(chǎng)景忧侧,我們來看一下源碼。

首先我們看一下onStart()方法調(diào)用的地方骏全,通過下面這段代碼苍柏,我們可以知道ActivityonStart()最初是通過Activity#performStart()方法調(diào)用過來的:

<!-- Activity.java -->
private Instrumentaion mInstrumentation;

final void performStart() {
    mInstrumentation.callActivityOnStart(this);
}

<!-- Instrumentaion.java -->
public void callActivityOnStart(Activity activity) {
   activity.onStart();
}

Activity#performStart()方法是由ActivityThread#performLaunchActivity(調(diào)過來的:

<!-- 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()
       ....
   }
}
//首先看一下調(diào)用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(); 
}
  • 通過上面這段代碼,我們可以得出以下幾點(diǎn)啟發(fā):
  • onStart()onResume()的過程中,還可能會(huì)回調(diào)onRestoreInstanceState/onPostCreate/onNewIntent/onActvitiyResult這幾個(gè)方法熄捍。
  • 如果應(yīng)用退到后臺(tái)烛恤,再次被啟動(dòng)(onNewIntent),或者通過startActivityForResult方法啟動(dòng)另一個(gè) Activity得到結(jié)果返回(onActivityResult)的時(shí)候余耽,在onStart()方法當(dāng)中得到的并不是這兩個(gè)回調(diào)的最新結(jié)果缚柏,因?yàn)樯厦娴倪@兩個(gè)方法并沒有調(diào)用,而在onResume()當(dāng)中碟贾,這點(diǎn)是可以得到保證的币喧。

3.3 protected void onResume()

  • 該方法被回調(diào)時(shí),意味著Activity已經(jīng)完全可見了袱耽,但這個(gè)完全可見的概念并不等同于Activity所屬的WindowAttach了杀餐,因?yàn)樵?code>Activity初次啟動(dòng)的時(shí)候,Attach的操作是在回調(diào)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()方法被回調(diào)時(shí)史翘,由于DecorView并不一定Attach了,因此這時(shí)候我們獲取布局內(nèi)某些View 的寬高得到的值有可能是不正確的冀续,既然onResume()當(dāng)中不能保證琼讽,那么onStart()方法也是同理,所有需要在attachToWindow之后才能執(zhí)行或是期望得到正確結(jié)果的操作都需要注意這一點(diǎn)洪唐。
  • onResume當(dāng)中钻蹬,我們一般會(huì)做這么一些事:在可見時(shí)重新拉取一些需要及時(shí)刷新的數(shù)據(jù)、注冊(cè) ContentProvider的監(jiān)聽桐罕,最重要的是在onPause()中的一些釋放操作要在這里面恢復(fù)回來脉让。

3.4 protected void onPause()

  • 該方法被回調(diào)時(shí),意味著Activity部分不可見功炮,例如一個(gè)半透明的界面覆蓋在了上面溅潜,這時(shí)候只要Activity仍然有一部分可見,那么它會(huì)一直保持在Paused狀態(tài)薪伏。
  • 如果用戶從Paused狀態(tài)回到Resumed狀態(tài)滚澜,只會(huì)回調(diào)onResume方法。
  • onPause()方法中嫁怀,應(yīng)該暫停正在進(jìn)行的頁面操作设捐,例如正在播放的視頻,或者釋放相機(jī)這些多媒體資源塘淑。
  • onPause()當(dāng)中萝招,可以保存一些必要數(shù)據(jù)到持久化的存儲(chǔ),例如正在編寫的信息草稿存捺。
  • 不應(yīng)該在這里執(zhí)行耗時(shí)的操作槐沼,因?yàn)樾陆缑鎲?dòng)的時(shí)候會(huì)先回調(diào)當(dāng)前頁面的onPause()方法曙蒸,所以如果進(jìn)行了耗時(shí)的操作,那么會(huì)影響到新界面的啟動(dòng)時(shí)間岗钩,官方文檔的建議是這些操作應(yīng)該放到 onStop()當(dāng)中去做纽窟,其實(shí)在onStop()中也不應(yīng)當(dāng)做耗時(shí)的操作,因?yàn)樗彩窃谥骶€程當(dāng)中的兼吓,而在主線程中永遠(yuǎn)不應(yīng)該進(jìn)行耗時(shí)的操作臂港。
  • 釋放系統(tǒng)資源,例如先前注冊(cè)的廣播视搏、使用的傳感器(如GPS)审孽、以及一些僅當(dāng)頁面獲得焦點(diǎn)時(shí)才需要的資源。
  • 當(dāng)處于Paused狀態(tài)時(shí)浑娜,Activity的實(shí)例是被保存在內(nèi)存中的瓷胧,因此在其重新回到Resumed狀態(tài)的過程中,不需要重新初始化任何的組件棚愤。

3.5 protected void onStop()

  • 該方法被回調(diào)時(shí),表明Activity已經(jīng)完全不可見了杂数。
  • 在任何場(chǎng)景下宛畦,系統(tǒng)都會(huì)先回調(diào)onPause(),之后再回調(diào)onStop()揍移。
  • 官方文檔有談到次和,當(dāng)onStop()執(zhí)行完之后,系統(tǒng)有可能會(huì)銷毀這個(gè)Activity實(shí)例那伐,在某些極端情況下踏施,有可能不會(huì)回調(diào)onDestroy()方法,因此罕邀,我們需要在onStop()當(dāng)中釋放掉一些資源來避免內(nèi)存泄漏畅形,而 onDestory()中需要釋放的是和Activity相關(guān)的資源,如線程之類的(這點(diǎn)平時(shí)在工作中很少用诉探,一般我們都是在onDestroy()中釋放所有資源日熬,而且也沒有去實(shí)現(xiàn)onStart() 方法,究竟什么時(shí)候不會(huì)走onDestroy()肾胯,這點(diǎn)值得研究竖席,目前的猜測(cè)是該Activity在別的地方被引用了,導(dǎo)致其不能回收)敬肚。
  • 當(dāng)ActivityStopped狀態(tài)回到前臺(tái)時(shí)毕荐,會(huì)先回調(diào)onRestart()方法,然而我們更多的是使用onStart() 方法作為onStop()的對(duì)應(yīng)關(guān)系艳馒,因?yàn)闊o論是從Stopped狀態(tài)憎亚,還是從Created狀態(tài)跳轉(zhuǎn)到Resumed狀態(tài),都是需要初始化必要的資源的,而它們經(jīng)過的共同路徑是onStart()虽填。

3.6 protected void onDestroy()

  • 該方法被回調(diào)時(shí)丁恭,表明Activity是真正要被銷毀了,
  • 此時(shí)應(yīng)當(dāng)釋放掉所有用到的資源斋日,避免內(nèi)存泄漏牲览。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市恶守,隨后出現(xiàn)的幾起案子第献,更是在濱河造成了極大的恐慌,老刑警劉巖兔港,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庸毫,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡衫樊,警方通過查閱死者的電腦和手機(jī)飒赃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來科侈,“玉大人载佳,你說我怎么就攤上這事⊥握唬” “怎么了蔫慧?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)权薯。 經(jīng)常有香客問我姑躲,道長(zhǎng),這世上最難降的妖魔是什么盟蚣? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任黍析,我火速辦了婚禮,結(jié)果婚禮上刁俭,老公的妹妹穿的比我還像新娘橄仍。我一直安慰自己,他們只是感情好牍戚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布侮繁。 她就那樣靜靜地躺著,像睡著了一般如孝。 火紅的嫁衣襯著肌膚如雪宪哩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天第晰,我揣著相機(jī)與錄音锁孟,去河邊找鬼彬祖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛品抽,可吹牛的內(nèi)容都是我干的储笑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼圆恤,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼突倍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起盆昙,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤羽历,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后淡喜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秕磷,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年炼团,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了澎嚣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瘟芝,死狀恐怖币叹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情模狭,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布踩衩,位于F島的核電站嚼鹉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏驱富。R本人自食惡果不足惜锚赤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望褐鸥。 院中可真熱鬧线脚,春花似錦、人聲如沸叫榕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽晰绎。三九已至寓落,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荞下,已是汗流浹背伶选。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工史飞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仰税。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓构资,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親陨簇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吐绵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容