詳解Activity&Fragment生命周期

謹(jǐn)以文章記錄學(xué)習(xí)歷程,如有錯(cuò)誤還請(qǐng)指明蛋辈。

Activity生命周期

首先放上Google Develop Guides中的Activity完整的生命周期示意圖:


回調(diào)初步解讀

  • onCreate():創(chuàng)建活動(dòng)時(shí)調(diào)用。

  • onStart():當(dāng)活動(dòng)進(jìn)入可見狀態(tài)時(shí)調(diào)用,使得活動(dòng)可見但不可與用戶交互坠七。

  • onResume():活動(dòng)進(jìn)入前臺(tái)時(shí)調(diào)用水醋,可與用戶交互。

  • onPause():活動(dòng)不持有用戶焦點(diǎn)但依然可見時(shí)調(diào)用彪置≈糇伲活動(dòng)仍可見,但停止與用戶交互拳魁,比如彈窗惶桐,鎖屏等

  • onStop():活動(dòng)不可見時(shí)調(diào)用

  • onDestroy():活動(dòng)退出,被銷毀時(shí)調(diào)用

  • onRestart():活動(dòng)由不可見重新返回前臺(tái)時(shí)調(diào)用潘懊。依次調(diào)用onRestart()->onStart()->onResume()

回調(diào)方法中進(jìn)行的操作

  • onCreate():在這個(gè)方法中姚糊,執(zhí)行基本的應(yīng)用程序啟動(dòng)邏輯,這種邏輯應(yīng)該只在活動(dòng)的整個(gè)生命周期中發(fā)生一次卦尊。如將數(shù)據(jù)綁定到ListView叛拷,聲明范圍變量等。同時(shí)該方法接收一個(gè)savedInstanceState參數(shù)岂却,是用來(lái)恢復(fù)之前保存過(guò)狀態(tài)的Bundle對(duì)象忿薇。后面我們會(huì)介紹。

  • onStart():該方法中初始化維護(hù)UI的組件躏哩,如注冊(cè)一個(gè)監(jiān)聽UI變化的廣播署浩。

  • onResume():在這個(gè)方法中,應(yīng)該初始化在onPause()中釋放的組件扫尺,如初始化camera筋栋,同時(shí)執(zhí)行活動(dòng)每次進(jìn)入前臺(tái)時(shí)候都需要的初始化操作,如開始動(dòng)畫與初始化哪些只有在獲取用戶焦點(diǎn)時(shí)才需要得到組件正驻,如上下文菜單弊攘。

  • onPause():釋放系統(tǒng)資源,例如廣播接收器姑曙、處理傳感器(如GPS)或任何可能影響電池壽命的資源襟交。

  • onStop():釋放幾乎所有不需要的資源,如上述onStart()中創(chuàng)建的廣播伤靠,同時(shí)在此方法中執(zhí)行耗時(shí)的釋放資源的操作捣域,如保存數(shù)據(jù),網(wǎng)絡(luò)調(diào)用宴合,數(shù)據(jù)庫(kù)事務(wù)等焕梅。同時(shí)很重要的一點(diǎn),需要在此方法中釋放可能導(dǎo)致內(nèi)存泄漏的資源卦洽,因?yàn)橄到y(tǒng)因?yàn)閮?nèi)存緊張而殺死活動(dòng)進(jìn)程時(shí)贞言,不會(huì)調(diào)用最后的onDestroy()方法。

  • onDestroy():釋放在onCreate()中初始化的活動(dòng)所能使用的全局資源阀蒂。

在任何一個(gè)生命周期回調(diào)方法中調(diào)用finish()方法時(shí)蜗字,系統(tǒng)會(huì)直接調(diào)用onDestroy()方法打肝,而跳過(guò)這之前的所有回調(diào)過(guò)程。

  • onRestart():由于onStart()的存在挪捕,這個(gè)方法好像沒(méi)什么使用場(chǎng)景。

為什么在onStop()中釋放耗時(shí)資源而不是在onPause()中争便?
原因:在兩個(gè)Activity A级零,B中,當(dāng)從A中startActivity()startActivityForResult()啟動(dòng)B時(shí)滞乙,分別以如下的順序調(diào)用生命周期的回調(diào)方法:

  • Activity A的onPause()
  • Activity B的onCreate()奏纪,onStart()onResume()依次執(zhí)行斩启,此時(shí)Activity B進(jìn)入前臺(tái)并獲得用戶焦點(diǎn)
  • 如果Activity A不再顯示在屏幕上序调,則調(diào)用其onStop()方法。

A的onStop()方法和B的onCreate()等一系列方法并非順序執(zhí)行,而是有重疊。因此當(dāng)onPause()方法中進(jìn)行耗時(shí)操作時(shí)酣难,會(huì)嚴(yán)重影響活動(dòng)之間的跳轉(zhuǎn)速度孽糖。

不同場(chǎng)景下回調(diào)方法的調(diào)用順序

  • 啟動(dòng)Activity
    onCreate()(創(chuàng)建)---> onStart()(可見,不可交互) ---> onResume()(前臺(tái)钧汹,可交互)

  • currentActivity被otherActivity覆蓋一部分,或鎖屏
    onPause()(失去用戶焦點(diǎn),但仍可見)

  • currentActivity由上述部分不可見狀態(tài)回到前臺(tái)或解鎖屏幕
    onResume()(前臺(tái)墩朦,持有用戶焦點(diǎn))

  • currentActivity轉(zhuǎn)到otherActivity界面,或按Home退回主界面翻擒,自身進(jìn)入后臺(tái)
    onPause()(失去用戶焦點(diǎn)氓涣,但仍可見)---> onStop()(不可見)

  • 由上述后臺(tái)狀態(tài)再次打開該活動(dòng)
    onRestart()(過(guò)渡狀態(tài),不清楚到底有什么用陋气。劳吠。。) ---> onStart()(可見恩伺,不可交互) ---> onResume()(前臺(tái)赴背,持有用戶焦點(diǎn))

  • currentActivity部分可見或后臺(tái)不可見時(shí),系統(tǒng)內(nèi)存不足時(shí)
    殺死當(dāng)前Activity晶渠,此時(shí)生命周期不會(huì)發(fā)生回調(diào)

  • 上述被殺死的活動(dòng)再次啟動(dòng)
    onCreate()(重新創(chuàng)建) ---> onStart()(可見凰荚,不可交互) ---> onResume()(前臺(tái),持有用戶焦點(diǎn))

  • 用戶退出currentActivity
    onPause()(失去用戶焦點(diǎn)褒脯,但仍可見) ---> onStop()(不可見) ---> onDestroy()

  • 多窗口下便瑟,ActivityA獲得焦點(diǎn)時(shí),點(diǎn)擊ActivityB
    對(duì)于ActivityA:onPause()(失去用戶焦點(diǎn)番川,但仍可見)
    對(duì)于ActivityB:onResume()(前臺(tái)到涂,持有用戶焦點(diǎn))


Fragment的生命周期

同樣脊框,還是先放上Google Develop Guides中的Fragment完整的生命周期示意圖:


回調(diào)解析

Activity中同名方法不在贅述

  • onAttach()
    Fragment和Activity建立關(guān)聯(lián)時(shí)調(diào)用(獲得activity的傳遞的值,如二者依靠回調(diào)通信時(shí)践啄,獲得activity的引用(將其轉(zhuǎn)型為callback回調(diào)接口))

  • onCreateView()
    為Fragment創(chuàng)建視圖(加載布局)時(shí)調(diào)用(給當(dāng)前的fragment繪制UI布局浇雹,可以使用線程更新UI)

  • onActivityCreated()
    當(dāng)Activity中的onCreate()方法執(zhí)行完后調(diào)用(表示activity執(zhí)行oncreate()方法完成了的時(shí)候會(huì)調(diào)用此方法)

  • onDestroyView()
    Fragment中的布局被移除時(shí)調(diào)用

  • onDetach()
    Fragment和Activity解除關(guān)聯(lián)的時(shí)候調(diào)用

不同場(chǎng)景下回調(diào)方法的調(diào)用順序

  • 創(chuàng)建一個(gè)fragment的時(shí)候
    創(chuàng)建過(guò)程:onAttach() ---> onCreate() ---> onCreateView() ---> onActivityCreated()
    顯示到前臺(tái):onStart() ---> onResume()

  • fragment進(jìn)入后臺(tái)
    onPause() ---> onStop()

  • fragment被銷毀
    onPause() ---> onStop() ---> onDestroyView() ---> onDestroy() ---> onDetach()

  • 鎖屏
    onPause() ---> onStop()

  • 解鎖
    onStart() ---> onResume()

  • 打開其他fragment(原始fragment被替換,或完全不可見)
    onPause() ---> onStop() ---> onDestroyView()

  • 上述條件下back回原始fragment
    onCreateView() ---> onActivityCreated() -> onStart()---> onResume()

  • Home回到桌面
    onPause() ---> onStop()

  • 上述回到原始fragment
    onStart() ---> onResume()

  • 退出應(yīng)用
    onPause() ---> onStop() --->onDestroyView()---> onDestroy() --->onDetach()


二者生命周期的聯(lián)系

老規(guī)矩屿讽,還是放上Google Develop Guides中的對(duì)比圖

生命周期對(duì)比

由于Android內(nèi)部機(jī)制(原理尚不知昭灵,未深入源碼做研究),fragment總是依附于activity而存在伐谈,不過(guò)需要注意的是activity的生命周期由系統(tǒng)控制烂完,而fragment則是由宿主activity控制,因此在activity進(jìn)入到某一狀態(tài)如created诵棵,系統(tǒng)會(huì)調(diào)用activity的onCreate()抠蚣,此時(shí)宿主activity會(huì)調(diào)用fragment的onAttach()...onActivityCreated()一系列方法,使得fragment快速跟上宿主履澳,與宿主activity保持一致狀態(tài)嘶窄。


關(guān)于Activity狀態(tài)保存與恢復(fù)

在上述生命周期中,我們有時(shí)會(huì)需要保存activity的狀態(tài)奇昙,比如我們正在某一文本框EditText中輸入文本時(shí)护侮,此時(shí)退出應(yīng)用之后再次打開時(shí),我們會(huì)發(fā)現(xiàn)文本框的內(nèi)容消失了储耐。消失了羊初。。消失了什湘。长赞。。
這種情況下闽撤,用戶體驗(yàn)顯然不會(huì)好得哆。因此Google引入了保存UI狀態(tài)這一概念。

保存狀態(tài)

復(fù)寫onSaveInstanceState()哟旗,傳入一個(gè)帶有狀態(tài)信息的Bundle對(duì)象贩据,代碼如下:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);


    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

保存狀態(tài)的時(shí)機(jī)

Activity容易被銷毀的時(shí)候調(diào)用:

  • 按下Home鍵:Activity進(jìn)入了后臺(tái)
  • 鎖屏:Activity進(jìn)入后臺(tái)
  • 啟動(dòng)其他Activity:Activity進(jìn)入后臺(tái)
  • 橫豎屏切換:銷毀并重建Activity實(shí)例

上述場(chǎng)景下,多數(shù)為當(dāng)系統(tǒng)內(nèi)存不足時(shí)闸餐,可能銷毀后臺(tái)低優(yōu)先級(jí)的Activity饱亮。

注意事項(xiàng)

在用戶主動(dòng)銷毀Activity時(shí)不會(huì)保存狀態(tài):

  • back
  • 調(diào)用finish()方法

方法調(diào)用時(shí)機(jī):

  • Android P之前:介于onStop()之前,但不確定在onPause()之前還是之后舍沙。
  • Android P中:在onStop()后調(diào)用

設(shè)有id的組件會(huì)自動(dòng)保存組件的狀態(tài)

恢復(fù)狀態(tài)

我們有兩種方式恢復(fù)狀態(tài):

  • onCreate()方法恢復(fù)
    需要注意的是近上,在嘗試讀取該對(duì)象時(shí),需要判斷其是否為空拂铡,空時(shí)則會(huì)創(chuàng)建該活動(dòng)的新實(shí)例壹无,而非恢復(fù)之前被銷毀活動(dòng)實(shí)例:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first


    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    // ...
}
  • 重寫onRestoreInstanceState()方法恢復(fù)
    只有在有待恢復(fù)的狀態(tài)時(shí)葱绒,系統(tǒng)才調(diào)用onRestoreInstanceState(),所以不需要檢查savedInstanceState是否為空:
public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

調(diào)用時(shí)機(jī)

  • 銷毀了之后重建的時(shí)候調(diào)用, 如果內(nèi)存充足, 系統(tǒng)沒(méi)有銷毀這個(gè) Activity, 就不需要調(diào)用
  • 橫豎屏切換時(shí)調(diào)用

總結(jié)

  • 本文盡可能詳細(xì)的對(duì)Activity和Fragment的生命周期斗锭,以及Activity的狀態(tài)保存與恢復(fù)作出了解析
  • 筆者水平有限地淀,如有錯(cuò)漏,歡迎指正拒迅。
  • 接下來(lái)我也會(huì)將所學(xué)的知識(shí)分享出來(lái)骚秦,有興趣可以繼續(xù)關(guān)注whd_Alive的Android開發(fā)筆記

歡迎關(guān)注whd_Alive的簡(jiǎn)書

  • 不定期分享Android開發(fā)相關(guān)的技術(shù)干貨,期待與你的交流璧微,共勉。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末硬梁,一起剝皮案震驚了整個(gè)濱河市前硫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌荧止,老刑警劉巖屹电,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異跃巡,居然都是意外死亡危号,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門素邪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)外莲,“玉大人,你說(shuō)我怎么就攤上這事兔朦⊥迪撸” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵沽甥,是天一觀的道長(zhǎng)声邦。 經(jīng)常有香客問(wèn)我,道長(zhǎng)摆舟,這世上最難降的妖魔是什么亥曹? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮恨诱,結(jié)果婚禮上媳瞪,老公的妹妹穿的比我還像新娘。我一直安慰自己胡野,他們只是感情好材失,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著硫豆,像睡著了一般龙巨。 火紅的嫁衣襯著肌膚如雪笼呆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天旨别,我揣著相機(jī)與錄音诗赌,去河邊找鬼。 笑死秸弛,一個(gè)胖子當(dāng)著我的面吹牛铭若,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播递览,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼叼屠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了绞铃?” 一聲冷哼從身側(cè)響起镜雨,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎儿捧,沒(méi)想到半個(gè)月后荚坞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菲盾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年颓影,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片懒鉴。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诡挂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出疗我,到底是詐尸還是另有隱情咆畏,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布吴裤,位于F島的核電站旧找,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏麦牺。R本人自食惡果不足惜钮蛛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剖膳。 院中可真熱鬧魏颓,春花似錦、人聲如沸吱晒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至叹话,卻和暖如春偷遗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背驼壶。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工氏豌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人热凹。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓泵喘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親般妙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子纪铺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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