一、Activity的生命周期全面分析
典型情況下的生命周期:在用戶參與的情況下,Activity所經(jīng)過(guò)的生命周期改變。
異常情況下的生命周期:Activity被系統(tǒng)回收或者設(shè)備的Configuration發(fā)生改變從而導(dǎo)致Activity被銷毀重建
1、典型情況下的生命周期分析

- onPause必須執(zhí)行完,新的Activity的onResume才會(huì)執(zhí)行。比如A打開B,生命周期順序是 A onPause->B onCreate ->B onStart ->B onResume ->A onStop。因此onPause不能做耗時(shí)操作,才能使新的Activity盡快顯示出來(lái)
- onStart表示Activity已經(jīng)可見但還在后臺(tái)我們看不見,沒(méi)有出現(xiàn)在前臺(tái)無(wú)法與用戶進(jìn)行交互。
- onResume表示Activity已經(jīng)出現(xiàn)在前臺(tái)且可以與用戶進(jìn)行交互
- Activity切換到后臺(tái)( 用戶打開新的Activity或者切換到桌面) ,onPause->onStop(如果新Activity采用了透明主題,則當(dāng)前Activity不會(huì)回調(diào)onStop)。
2、異常情況下的生命周期分析
2.1、情況1:系統(tǒng)配置發(fā)生改變導(dǎo)致Activity被殺死并重新創(chuàng)建
比如橫豎屏切換,默認(rèn)情況下,Activity就會(huì)銷毀重建。生命周期如下

當(dāng)系統(tǒng)配置發(fā)生改變導(dǎo)致Activity被銷毀,onPause->onStop->onDestroy,還會(huì)調(diào)用onSaveIntanceState保存當(dāng)前Activity的狀態(tài),時(shí)機(jī)是在onStop之前(僅僅出現(xiàn)在Activity異常終止的情況)。
當(dāng)Activity被重建時(shí),會(huì)調(diào)用onRestoreInstanceState,時(shí)機(jī)是在onStop之后,并把onSaveIntanceState中保存的Bundle對(duì)象同時(shí)傳遞給onRestoreInstanceState和onCreate。注意,onRestoreInstanceState被調(diào)用,其入?yún)undle一定有值,但是onCreate的Bundle入?yún)⒖赡軙?huì)null,建議采用onRestoreInstanceState去恢復(fù)數(shù)據(jù)。
每個(gè)View都有onSaveIntanceState和onRestoreInstanceState方法,系統(tǒng)會(huì)自動(dòng)幫我們做一些恢復(fù)工作,具體恢復(fù)哪些數(shù)據(jù),要看每個(gè)View的實(shí)現(xiàn)。大致的工作流程如下:Activity意外終止,調(diào)用onSaveIntanceState去保存數(shù)據(jù),然后Activity委托Window去保存數(shù)據(jù),Window再委托上面的頂層容器(ViewGroup,一般為DecorView)去保存數(shù)據(jù),頂層容器再去一一通知它的子元素來(lái)保存數(shù)據(jù)。(這是一種典型的委托思想,事件分發(fā)和View的繪制過(guò)程也是采用類似的思想)
系統(tǒng)只有在Activity異常終止的情況下,才會(huì)調(diào)用onSaveIntanceState和onRestoreInstanceState方法,其他情況不會(huì)調(diào)用。
2.2、情況2:內(nèi)存資源不足,導(dǎo)致低優(yōu)先級(jí)Activity被殺死
Activity按照優(yōu)先級(jí)分類:
1)前臺(tái)Activity
2)可見非前臺(tái)Activity
3)后臺(tái)Activity
系統(tǒng)內(nèi)存不足時(shí),低優(yōu)先級(jí)的Activity所在進(jìn)程會(huì)被殺死,并通過(guò)onSaveIntanceState和onRestoreInstanceState來(lái)存儲(chǔ)和恢復(fù)數(shù)據(jù)。
3、系統(tǒng)配置發(fā)生改變,Activity如何不重新創(chuàng)建?
在Activity的配置中,配置屬性android:configChanges="orientation|screenSize",可以在屏幕旋轉(zhuǎn)的時(shí)候,不重新創(chuàng)建Activity,取而代之的是調(diào)用Activity的onConfigurationChanged方法。
其他可以配置項(xiàng)目如下表所示
| 項(xiàng)目 | 含義 |
|---|---|
| locale | 一般指切換了系統(tǒng)語(yǔ)言 |
| keboardHidden | 鍵盤的可訪問(wèn)性發(fā)生了變化 |
| orientation | 屏幕方向發(fā)生了變化 |
| screenSize | 屏幕尺寸信息發(fā)生了變化,旋轉(zhuǎn)屏幕尺寸信息就會(huì)發(fā)生變化。和編譯版本有關(guān),若編譯版本小于13,不會(huì)導(dǎo)致Activity的重啟;若大于13,則會(huì)導(dǎo)致Activity的重啟 |
二、Activity的啟動(dòng)模式
1、Activity的LaunchMode
四種啟動(dòng)模式:standard、singleTop、singleTask和singleInstance。
1.1、standard
默認(rèn)模式,誰(shuí)啟動(dòng)了Activity,那么這個(gè)Activity就運(yùn)行在啟動(dòng)它的那個(gè)Activity所在的棧中。非Activity類型的Context(如:ApplicationContext)并沒(méi)有所謂的任務(wù)棧,所以就會(huì)有問(wèn)題。
1.2、singleTop
棧頂復(fù)用模式。新的Activity位于任務(wù)棧的頂部,那么此Activity不會(huì)重新創(chuàng)建(onCreate、onStart不會(huì)調(diào)用),此時(shí)onNewIntent(Intent intent)會(huì)被調(diào)用,入?yún)⒕褪俏覀冋?qǐng)求的信息。
1.3、singleTask
棧內(nèi)復(fù)用模式。比如啟動(dòng)ActivityA,系統(tǒng)會(huì)先找A想要的任務(wù)棧,若不存在,則創(chuàng)建任務(wù)棧、A實(shí)例、入棧;若存在,棧中已經(jīng)存在A實(shí)例,移除A之上的元素,使A在棧頂,并調(diào)用onNewIntent,否則創(chuàng)建A實(shí)例,入棧。
1.4、singleInstance
加強(qiáng)的singTask模式,加強(qiáng)一點(diǎn):此類Activity只能單獨(dú)的位于一個(gè)任務(wù)棧中,后續(xù)的請(qǐng)求均不會(huì)創(chuàng)建新的Activity,除非這個(gè)任務(wù)棧被銷毀。
1.5、什么是Activity所需的任務(wù)棧?
TaskAffinity:任務(wù)相關(guān)性,標(biāo)識(shí)了一個(gè)Activity所需要的任務(wù)棧的名字,默認(rèn)情況下是包名。必須和singleTask啟動(dòng)模式或者allowTaskReparenting屬性配對(duì)使用,否則沒(méi)有意義。
任務(wù)棧分為前臺(tái)任務(wù)棧和后臺(tái)任務(wù)棧,后臺(tái)任務(wù)棧中的Activity處于暫停狀態(tài),用戶可以通過(guò)切換將后臺(tái)任務(wù)棧調(diào)到前臺(tái)。
TaskAffinity和allowTaskReparenting結(jié)合使用:現(xiàn)在有2個(gè)應(yīng)用A和B,A啟動(dòng)了B的Activity C,然后按Home鍵回到桌面,然后單擊桌面圖標(biāo)啟動(dòng)B,此時(shí)并不是啟動(dòng)B的主Activity,而是重新顯示了Activity C或者說(shuō),C從A的任務(wù)棧轉(zhuǎn)移到了B的任務(wù)棧??梢赃@么理解,由于A啟動(dòng)了C,這個(gè)C只能運(yùn)行在A所在的任務(wù)棧中,但是C是屬于B應(yīng)用的,正常情況下,它的TaskAffinity應(yīng)該是B的包名。所以,B被啟動(dòng)之后,B會(huì)創(chuàng)建自己的任務(wù)棧,此時(shí)系統(tǒng)發(fā)現(xiàn)C原本想要的任務(wù)棧已經(jīng)有了,就會(huì)把C從A的任務(wù)棧中轉(zhuǎn)移過(guò)。
1.6、指定啟動(dòng)模式的兩種方式
第一種:通過(guò)AndroidMenifest指定android:launchMode="singTask"
第二種:通過(guò)Intent的addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
2、Activity的Flags
Flags有很多,有些可以設(shè)定Activity的啟動(dòng)模式,有些可以影響Activity的運(yùn)行狀態(tài)。
FLAG_ACTIVITY_NEW_TASK
為Activity指定“singleTask”啟動(dòng)模式
FLAG_ACTIVITY_SINGLE_TOP
為Activity指定“singleTop”啟動(dòng)模式
FLAG_ACTIVITY_CLEAR_TOP
具有此標(biāo)記的Activity在啟動(dòng)時(shí),同一個(gè)任務(wù)棧中位于它上面的都要出棧。與singleTask一起使用,若實(shí)例已經(jīng)存在,會(huì)調(diào)用newIntent方法;若被啟動(dòng)的Activity是standard,則它自己也會(huì)出棧,然后重新創(chuàng)建一個(gè)新的Activity實(shí)例入棧。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
等價(jià)于android:excludeFromRecents="true",表明此Activity不會(huì)出現(xiàn)再歷史Activity列表中。
三、IntentFilter的匹配規(guī)則
Activity的啟動(dòng)分為顯式調(diào)用和隱式調(diào)用。隱式調(diào)用需要Intent能夠匹配目標(biāo)組件的IntentFilter中設(shè)置的過(guò)濾信息,不匹配將無(wú)法啟動(dòng)目標(biāo)Activity。IntentFilter的過(guò)濾信息有action、category、data。
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<category android:name="com.hilton.controlpanel.category.SELF_MAINTAIN" />
<data android:scheme="file" />
</intent-filter>
1、action的匹配規(guī)則
是一個(gè)區(qū)分大小寫的字符串,一個(gè)過(guò)濾規(guī)則中可以有多個(gè)action。
匹配要求:Intent中的action存在,且能夠和過(guò)濾規(guī)則中的任何一個(gè)action相同即可匹配成功。
2、category的匹配規(guī)則
是一個(gè)字符串,一個(gè)過(guò)濾規(guī)則中可以有多個(gè)category。
匹配要求:Intent可以沒(méi)有category,但是如果有,每一個(gè)都要和過(guò)濾規(guī)則中任何一個(gè)的匹配。在startActivity或者startActivityForResult的時(shí)候,會(huì)默認(rèn)加上“android.inent.category,DEFULT”,所以必須在intent-filter中指定這個(gè)category。
3、data的匹配規(guī)則
由兩部分組成:mimeType和URI。一個(gè)過(guò)濾規(guī)則中可以有多個(gè)。
匹配要求:Intent中必須有,且和過(guò)濾規(guī)則中的一個(gè)相匹配。
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string"/>
3.1、mimeType
指媒體類型,如 image/jpeg、vide/*等,可以表示圖片、文本、視頻等不同的媒體格式、
<data android:mimeType="image/*"/>
如上匹配規(guī)則指定了媒體類型為所有類型的圖片,雖然沒(méi)有指定URI,但是卻默認(rèn)為content和file。Intent中的URI部分的scheme必須為content或者file才能匹配。如下:
intent.setDataAndType(Uri.parse("file://abc"),"image/png")
setDataAndType(Uri data, String type)指定Data和Type屬性,因?yàn)?code>setAction(String action)和addCategory(String category)2個(gè)方法會(huì)相互覆蓋,所以當(dāng)要指定Data和Type時(shí),使用這個(gè)方法
3.2、URI
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
scheme:URI的模式,如http、file、content。沒(méi)有指定,則URI無(wú)效。
host:URI的主機(jī)名。沒(méi)有指定,則URI無(wú)效。
port:URI中的端口號(hào),可以沒(méi)有。
path:表示完整的路徑信息。
pathPattern:表示完整的路徑信息,建議包含通配符“*”(表示0個(gè)或多個(gè)任意字符)。
pathPrefix:表示路徑的前綴信息。
<data android:scheme="file" android:host="www.baidu.com"/>
等價(jià)于
<data android:scheme="file"/>
<data android:host="www.baidu.com"/>
參考文獻(xiàn)
《Android開發(fā)藝術(shù)探索》