一.典型情況下的生命周期
- onCreat: 表示Activity正在被創(chuàng)。再次方法中雏胃,我們可以做一些初始化工作遗嗽,例如調(diào)用setContentView去加載界面布局資源、初始化Activity所需數(shù)據(jù)等臣缀。
- onRestart:表示Activity正在重新啟動坝橡。一般情況下,當(dāng)Activity從不可見變?yōu)榭梢姞顟B(tài)時精置,此方法就會被調(diào)用计寇。這種情況是由于用戶操作導(dǎo)致,一般是由于用戶點擊的home鍵或點開了一個新的Activity,這時當(dāng)前Activity就會暫停番宁,就是onPause和onStop被執(zhí)行了元莫,接著用戶又回到這個Activity,就會出現(xiàn)該情況贝淤。
- onStart:表示Activity正在被啟動柒竞,即將開始。這時的Activity已經(jīng)可見了播聪,但沒有出現(xiàn)在前臺朽基,無法和用戶交互。
- onResume:表示Activity已經(jīng)可見离陶,并出現(xiàn)在前臺開始活動稼虎。onStart和onResume都表示Activity已經(jīng)可見,區(qū)別是招刨,onStart的時候Activity在后臺霎俩,而onResume的時候Activity位于前臺。
- onPause:表示Activity正在停止沉眶。此時可以做一些數(shù)據(jù)儲存打却,停止動畫等操作,但注意不能太耗時谎倔,因為這樣會影響新的Activity顯示柳击,因為onPause必須先執(zhí)行完,新的Activity的onResume才會執(zhí)行片习。正常情況下捌肴,緊接著onStop就會被調(diào)用,在特殊情況下藕咏,如果此時快速回到當(dāng)前Activity状知,那么onRestart會被調(diào)用,這是一種極端情況孽查,用戶操作很難重現(xiàn)饥悴。
- onStop:表示Activity即將停止,可以做一些稍微重量級的工作卦碾,但同樣不能太耗時铺坞。onStop和onPause的區(qū)別是,onPause的時候洲胖,Activity在前臺济榨,還能與用戶交互,而onStop的時候绿映,Activity就位于后臺了擒滑。
-
onDestory:表示Activity即將被銷毀腐晾。我們可以在這個做一些回收工作和最終的資源釋放。
Activity生命周期切換過程.jpg
針對上圖丐一,附加說明幾點:
(1)用戶打開新的Activity或點擊Home鍵時藻糖,回調(diào)如下:onPause -> onStop。這里有一特殊情況库车,若新的Activity采用了透明主題巨柒,則當(dāng)前Activity不會調(diào)用onStop。
(2)當(dāng)用戶再次回到Activity時柠衍,回調(diào)如下:onRestart -> onStart -> onResume洋满。
(3)當(dāng)用戶點擊back鍵時,回調(diào)如下:onPause -> onStop -> onDestroy珍坊。
(4)從整個生命周期來說牺勾,onCreate和onDestroy配對,標識Activity的創(chuàng)建與銷毀阵漏,且只能調(diào)用一次驻民;從Activity是否可見來看,onStart和onStop是配對的履怯,這兩個方法會隨用戶操作而多次被調(diào)用回还;從Activity是否位于前臺來說,onResume和onPause是配對的叹洲,這兩個方法也會隨用戶操作而多次被調(diào)用懦趋。
二.異常情況下的生命周期
情況1:資源相關(guān)的系統(tǒng)配置發(fā)生改變導(dǎo)致Activity被殺死并重新創(chuàng)建
舉例來說,當(dāng)前Activity處于豎屏狀態(tài)疹味,若突然旋轉(zhuǎn)屏幕,由于配置發(fā)生改變帜篇,默認情況下糙捺,Activity就會被銷毀并重新創(chuàng)建。這時笙隙,如果我們不對Activity做特殊處理洪灯,那么Activity的生命周期就會如下圖所示。
(1)當(dāng)系統(tǒng)配置發(fā)生改變后竟痰,Activity會被銷毀签钩,其onPause、onStop坏快、onDestroy會被調(diào)用铅檩,由于Activity是在異常情況下終止,系統(tǒng)會調(diào)用onSaveInstanceState來保存當(dāng)前Activity的狀態(tài)莽鸿,此方法的調(diào)用時機是在onStop之前昧旨,它和onPause沒有既定的時序關(guān)系拾给。需要強調(diào)的是,這個方法在正常情況下系統(tǒng)不會調(diào)用兔沃。
(2)當(dāng)Activity被重建時蒋得,系統(tǒng)會調(diào)用onRestoreInstanceState,并把Activity銷毀時onSaveInstanceState方法所保存的bundle對象作為參數(shù)傳遞給onRestoreInstanceState和onCreate方法乒疏。因此额衙,我們可以從onRestoreInstanceState和onCreate方法來判斷Activity是否被重建。如果被重建怕吴,我們則可以取出之前保存的數(shù)據(jù)并恢復(fù)窍侧。從時序上看,onRestoreInstanceState是在onStart之后被調(diào)用械哟。
(3)在onSaveInstanceState和onRestoreInstanceState方法中疏之,系統(tǒng)會自動為我們做一定的恢復(fù)工作。例如暇咆,Activity在異常情況下重新創(chuàng)建時锋爪,系統(tǒng)會默認保存當(dāng)前Activity的視圖結(jié)構(gòu),并在Activity重啟后恢復(fù)這些數(shù)據(jù)爸业,比如文本框中輸入的數(shù)據(jù)其骄,ListView滾動位置等。具體對某一特定View系統(tǒng)能恢復(fù)那些數(shù)據(jù)扯旷,可以查看View的源碼(和Activity一樣拯爽,每個View都有onSaveInstanceState和onRestoreInstanceState方法)。
(4)關(guān)于保存和恢復(fù)View層次機構(gòu)钧忽,系統(tǒng)工作流程如下:首先Activity意外終止毯炮,Activity會調(diào)用onSaveInstanceState去保存數(shù)據(jù),然后Activity會委托Window來保存數(shù)據(jù)耸黑,接著Window會委托頂層容器去保存數(shù)據(jù)桃煎。頂層容器是個ViewGroup,一般來說很可能是個DecorView大刊。最后为迈,頂層容器再一一通知子元素來保存數(shù)據(jù),這樣整個數(shù)據(jù)保存過程就結(jié)束了缺菌『可以看出,這是一種典型的委托思想伴郁,上層委托下層耿战,父容器委托子元素。這種思想在Android中有很多的應(yīng)用蛾绎,比如View的繪制過程昆箕、時間分發(fā)等等都采用了類似思想鸦列。
情況2:資源內(nèi)存不足導(dǎo)致低優(yōu)先級Activity被殺死
該情況我們不好模擬,但其儲存模式和情況1完全一致鹏倘。Activity的優(yōu)先級從高到低薯嗤,可分為如下三種:
(1)前臺Activity——正在和用戶交互的Activity,這種優(yōu)先級最高纤泵。
(2)可見但非前臺Activity——例如Activity彈出了一個對話框骆姐,導(dǎo)致Activity可見但位于后臺無法和用戶交互,比如執(zhí)行了onPause捏题,優(yōu)先級次之玻褪。
(3)后臺Activity——已經(jīng)被暫停的Activity,比如執(zhí)行了onStop公荧,這種優(yōu)先級最低带射。
當(dāng)系統(tǒng)內(nèi)存不足時,系統(tǒng)會按照上述優(yōu)先級去殺死目標Activity所在進程循狰,并后續(xù)通過onSaveInstanceState和onRestoreInstanceState方法來儲存和恢復(fù)數(shù)據(jù)窟社。若一個進程中沒有四大組件在執(zhí)行,那么這個進程將很快被殺死绪钥,較好的方法是將后臺工作放入Service中灿里,從而保證進程有一定優(yōu)先級,這樣就不會輕易被系統(tǒng)殺死了程腹。
那么當(dāng)系統(tǒng)配置發(fā)生改變后匣吊,什么方法才能讓Activity不被重新創(chuàng)建呢?方法是這樣的寸潦,我們可以給Activity指定configChanges屬性色鸳。例如不想讓Activity在屏幕旋轉(zhuǎn)時重建,我們就可以給configChanges屬性添加orientation這個值见转,如下缕碎。
android:configChanges="orientation"
若我們想指定多個值,可以使用“|”連接起來池户,如下。
android:configChanges="orientation|keyboardHidden"
系統(tǒng)配置中所含項目有很多凡怎,下面介紹了每個項目的含義校焦。
- “mcc“ 移動國家號碼,由三位數(shù)字組成统倒,每個國家都有自己獨立的MCC寨典,可以識別手機用戶所屬國家。
- “mnc“ 移動網(wǎng)號房匆,在一個國家或者地區(qū)中耸成,用于區(qū)分手機用戶的服務(wù)商报亩。
- “l(fā)ocale“ 所在地區(qū)發(fā)生變化。
- “touchscreen“ 觸摸屏已經(jīng)改變井氢。(這不應(yīng)該常發(fā)生弦追。)
- “keyboard“ 鍵盤模式發(fā)生變化,例如:用戶接入外部鍵盤輸入花竞。
- “keyboardHidden“ 用戶打開手機硬件鍵盤劲件。
- “navigation“ 導(dǎo)航型發(fā)生了變化。(這不應(yīng)該常發(fā)生约急。)
- “orientation“ 設(shè)備旋轉(zhuǎn)零远,橫向顯示和豎向顯示模式切換。
- “fontScale“ 全局字體大小縮放發(fā)生改變厌蔽。
- “screenSize” 屏幕尺寸信息發(fā)生改變牵辣,和屏幕方向無關(guān)僅表示屏幕物理尺寸改變。當(dāng)minSdkVersion一個小于等于13奴饮,為防止旋轉(zhuǎn)屏幕時Activity重啟纬向,除了“orientation“,我們還要加上“screenSize”拐云。
我們常用的時local罢猪,orientation,keyboardHidden這三個選項叉瘩。
三.Activity的啟動模式
為什么需要啟動模式膳帕,因為在默認情況下,當(dāng)我們多次啟動同一Activity時薇缅,系統(tǒng)會創(chuàng)建多個實例并把它們一一入棧危彩,而當(dāng)我們點擊back鍵時,這些Activity會一一回退泳桦。任務(wù)棧是一種“后進先出”的棧結(jié)構(gòu)汤徽,每按一下back鍵就會有一個Activity出棧,直到椌淖空谒府,系統(tǒng)會回收這個任務(wù)棧。上述是在Activity為默認啟動模式時會出現(xiàn)的情況浮毯。
目前Activity有四種啟動模式:standard完疫、singleTop、singleTask债蓝、singleInstance壳鹤。
1.Standard
標準模式价捧。夜視系統(tǒng)的默認模式祷愉。每次啟動一個Activity都會重新創(chuàng)建一個實例与纽,無論該Activity是否已經(jīng)存在兔簇。被創(chuàng)建的實例的onCreate,onStart锹淌,onResume都會被調(diào)用匿值。如果Activity A啟動Activity B(B為標準模式),則B就會進入A所在的任務(wù)棧中葛圃。
2.singleTop
棧頂復(fù)用模式千扔。在此種模式下,如果新Activity已經(jīng)位于任務(wù)棧棧頂库正,那么此Activity不會被重新創(chuàng)建曲楚,同時它的onNewIntent方法會被回調(diào),通過此方法的參數(shù)我們能取出當(dāng)前請求的信息褥符。如果新Activity已經(jīng)存在但不位于棧頂龙誊,那么新Activity仍然會被重新創(chuàng)建。
3.singleTask
棧內(nèi)復(fù)用模式喷楣。這是一種單實例模式趟大,在此模式下,只要Activity存在于一個棧中铣焊,那么多次啟動這個Activity都不會被重新創(chuàng)建實例逊朽。下面我通過幾個例子來更詳細講解singleTask的含義。(下面的Aty為Activity簡稱)
- 若當(dāng)前S1棧內(nèi)的情況為ABC曲伊,這時Activity D以singleTask模式請求啟動叽讳,它需要的任務(wù)棧為S2。由于S2與實例D均不存在坟募,系統(tǒng)會先創(chuàng)建任務(wù)棧S2岛蚤,再創(chuàng)建D的實例并入棧到S2內(nèi)。(無棧懈糯,無Aty涤妒,先建棧,再建Aty并入棧)
- 若前面的情況相同赚哗,這時這時Activity D需要的任務(wù)棧為S1她紫。由于S1已存在。系統(tǒng)會創(chuàng)建D的實例并入棧到S1內(nèi)屿储。(有棧犁苏,無Aty,建Aty并入棧)
- 若S1內(nèi)仍未ABC扩所,這時Activity B以singleTask模式請求啟動,它需要的任務(wù)棧為S1朴乖。由于S1與實例B均存在祖屏,此時B不會被重建助赞,系統(tǒng)會把B切換到棧頂位置并調(diào)用其onNewIntent方法,同時由于singleTask默認具有clearTop效果袁勺,會導(dǎo)致棧內(nèi)B上面的Activity全部出戰(zhàn)雹食。于是最終S1內(nèi)情況為BC。(有棧期丰,有Aty群叶,將A置頂且Aty以上所有Aty全部出棧)
- singleTask啟動模式中,Activity所需任務(wù)棧如何來制定呢钝荡?通過參數(shù):TaskAffinity街立,可以翻譯為任務(wù)相關(guān)性。這個參數(shù)可以標識Activity所需任務(wù)棧名字埠通,默認情況下赎离,所有Activity所需的任務(wù)棧名字為應(yīng)用的包名。當(dāng)然端辱,我們也可以自己指定梁剔,指定的屬性值必須不能與包名一樣,否則相當(dāng)于沒指定舞蔽。TaskAffinity主要和singleTask啟動模式或allowTaskReparenting屬性配對使用荣病,在其他情況下無意義。
①TaskAffinity和singleTask配對使用渗柿,Activity會運行在TaskAffinity指定的任務(wù)棧中个盆。
②TaskAffinity和allowTaskReparenting結(jié)合時,情況較復(fù)雜做祝,有奇效砾省。當(dāng)A應(yīng)用啟動了B應(yīng)用的某個Activity后,這時Activity會進入A應(yīng)用任務(wù)棧中混槐,若此Activity的allowTaskReparenting屬性為true编兄,那么當(dāng)應(yīng)用B被啟動后,此Activity會直接從A應(yīng)用任務(wù)棧轉(zhuǎn)移至B應(yīng)用的任務(wù)棧中声登。
4.singleInstance
單實例模式狠鸳。這是一種加強的singleTask模式。它除了具有sigleTask所有特性外悯嗓,還增加了一點件舵,就是具有此種模式的Activity只能單獨位于一個任務(wù)棧中。打個比方來說脯厨,若Activity A為singleInstance模式铅祸,當(dāng)A啟動,系統(tǒng)會為他創(chuàng)建一個新的任務(wù)棧并將A入棧,由于棧內(nèi)復(fù)用特性临梗,后續(xù)請求均不會創(chuàng)建A涡扼,除非這個獨特的任務(wù)棧被系統(tǒng)銷毀了。
指定啟動模式的方法
1.第一種是在Android的Menifest通過launchMode屬性來指定盟庞,如下:
<activity android:name=".SecondActivity"
android:launchMode="singleTask"
android:taskAffinity="MyActivity"/>
2.另一種是在Activity內(nèi)通過在Intent設(shè)置標志位來指定吃沪,如下:
Intent intent = new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
3.這兩種方式都可以指定Activity的啟動模式,但二者有區(qū)別什猖。其一票彪,優(yōu)先級上來講,第二種方法要高于第一種不狮;其二降铸,限定范圍上,第一種方法無法直接設(shè)定FLAG_ACTIVITY_CLEAR_TOP標識荤傲,而第二種方法無法指定singleInstance模式垮耳。
四.Activity的Flags
Activity的Flags有很多,我們主要分析一些較常用的標記位遂黍。
標記位的做有很多终佛,有的標記為可以設(shè)定Activity的啟動模式,比如FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_SINGLE_TOP等雾家;還有的標記位可以影響Activity的運行狀態(tài)铃彰,比如FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS等。
大部分情況下芯咧,我們不需要為Activity設(shè)置標記位牙捉,在使用標記位時,要注意有的標記位是系統(tǒng)內(nèi)部使用的敬飒,應(yīng)用程序不需要手動設(shè)置這些標記位以防出現(xiàn)問題邪铲。
-
FLAG_ACTIVITY_NEW_TASK
此標記位作用是為Activity指定singleTask啟動模式,其效果合在XML中指定該啟動模式相同无拗。 -
FLAG_ACTIVITY_SINGLE_TOP
此標記位作用是為Activity指定singleInstance啟動模式带到,其效果合在XML中指定該啟動模式相同。 -
FLAG_ACTIVITY_CLEAR_TOP
具有該標記位的Activity啟動時英染,若啟動的Activity為singleTask啟動模式揽惹,則同一任務(wù)棧內(nèi)它之上的Activity都會出棧;若啟動的Activity為standard啟動模式四康,則同一任務(wù)棧內(nèi)連同它之上的Activity都會出棧搪搏,系統(tǒng)會重建一個新的Activity入棧。 -
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
設(shè)置該標記位的Activity不會出現(xiàn)在歷史Activity列表闪金,當(dāng)某些情況下我們不希望用戶通過歷史列表回到我們這個Activity時較為有用疯溺。它等同于在XML中指定屬性android:excludeFromRecents="true"。
幫忙點個贊再走嘛~
點贊暴富- 【個人主頁】 點擊關(guān)注我,TuTu兔 會持續(xù)更新分享更多姿勢喲~ (????) ~