一,安卓的七大生命周期
onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy | onRestart
onCreate:Activity正在被創(chuàng)建
onStart:已經(jīng)可見(jiàn)但是還不在前臺(tái)庭瑰,無(wú)法交互
onResume:已經(jīng)可以開(kāi)始交互了
onPause:Activity正在停止星持,onStop會(huì)被緊接著調(diào)用。不應(yīng)該在這個(gè)階段做耗時(shí)操作弹灭,只有這個(gè)方法執(zhí)行完督暂,新的Activity的onResume才能被執(zhí)行
onStop:Activity即將停止,可以做一些重量級(jí)回收工作鲤屡,也不能太耗時(shí)
onDestroy:Activity即將被銷毀损痰,可以做一些資源釋放和回收工作
onRestart:表示Activity重新啟動(dòng),一般由不可見(jiàn)變?yōu)榭梢?jiàn)時(shí)被調(diào)用
注意事項(xiàng):
- 用戶打開(kāi)的新的Activity是透明主題酒来,原來(lái)的Activity的onStop不會(huì)被調(diào)用
- 回到上一個(gè)Activity卢未,該Activity生命周期回調(diào):onRestart -> onStart -> onResume
- 當(dāng)用戶按下返回鍵,當(dāng)前Activity生命周期回調(diào):onPause -> onStop -> onDestroy
- Activity A啟動(dòng)Activity B堰汉,生命周期:A onPause -> B onCreate -> B onStart -> B onResume -> A onStop
- Activity被系統(tǒng)回收后重新啟動(dòng)生命周期從頭走一遍
- onStart和onStop是關(guān)于Activity可見(jiàn)不可見(jiàn)而調(diào)用的辽社,onResume和onPause是關(guān)于Activity是否位于前臺(tái)來(lái)調(diào)用的,因此這四個(gè)方法都會(huì)隨著用戶熄滅屏幕翘鸭、亮起屏幕而頻繁調(diào)用
二滴铅,安卓異常情況下的生命周期
- 當(dāng)系統(tǒng)配置發(fā)生改變后,Activity會(huì)被銷毀就乓,其onPause汉匙、onStop、onDestroy均會(huì)被調(diào)用生蚁,同時(shí)由于Activity是在異常情況下終止的噩翠,系統(tǒng)會(huì)調(diào)用onSaveInstanceState來(lái)保存當(dāng)前Activity的狀態(tài)。這個(gè)方法的調(diào)用時(shí)機(jī)是在onStop之前邦投,它和onPause沒(méi)有既定的時(shí)序關(guān)系伤锚,它既可能在onPause之前調(diào)用,也可能在onPause之后調(diào)用志衣。需要強(qiáng)調(diào)的一點(diǎn)是屯援,這個(gè)方法只會(huì)出現(xiàn)在Activity被異常終止的情況下猛们,正常情況下系統(tǒng)不會(huì)回調(diào)這個(gè)方法∧螅總結(jié)如下:
(onPause/onSaveInstanceState)->(onPause/onSaveInstanceState)-> onStop -> onDestroy - 異常情況終止下弯淘,onSaveInstanceState保存的數(shù)據(jù)可以通過(guò)onCreate和onRestoreInstanceState的形參Bundle傳入。因此在onCreate中對(duì)Bundle進(jìn)行判空可以判斷是否是異常終止然后重建的徘铝,而onRestoreInstanceState在異常情況下重建必然會(huì)被調(diào)用耳胎,所以傳入的Bundle一定不為空。官方推薦在onRestoreInstanceState方法中進(jìn)行數(shù)據(jù)恢復(fù)惕它。onRestoreInstanceState方法調(diào)用時(shí)機(jī)在onStart之后怕午。
- 注意:onSaveInstanceState和onRestoreInstanceState方法只有在Activity被銷毀并且有機(jī)會(huì)重新顯示的情況下才會(huì)被調(diào)用。例如屏幕旋轉(zhuǎn)淹魄,Activity被銷毀但是又要立即展示出來(lái)郁惜;資源不足,低優(yōu)先級(jí)被回收甲锡,但是用戶可能還會(huì)回到那個(gè)界面兆蕉,還有機(jī)會(huì)展示。所以正常的銷毀是不會(huì)調(diào)用這兩個(gè)方法的缤沦!
- 關(guān)于Activity的優(yōu)先級(jí):
4.1 前臺(tái)Activity虎韵,優(yōu)先級(jí)最高
4.2 可見(jiàn)但非前臺(tái)Activity,例如這個(gè)Activity彈出一個(gè)Dialog缸废,這時(shí)候Activity不能交互包蓝,但是可見(jiàn),優(yōu)先級(jí)其次
4.3 后臺(tái)Activity企量,已經(jīng)位于后臺(tái)被暫停测萎,例如執(zhí)行了onStop,優(yōu)先級(jí)最低 - 對(duì)于系統(tǒng)配置變更后Activity其實(shí)是有辦法不進(jìn)行重建的届巩,在清單文件中對(duì)應(yīng)的Activity加上
android:configChanges="orientation"
硅瞧,但是當(dāng)minSdkVersion或者targetSdkVersion大于13時(shí),為了防止重建還得加上screenSize
恕汇,也就是這樣了:“android:configChanges="orientation|screenSize”
三腕唧,安卓啟動(dòng)模式
standard:默認(rèn)啟動(dòng)模式,每次啟動(dòng)就在啟動(dòng)它的那個(gè)Activity所在的任務(wù)棧的棧頂添加一個(gè)Activity實(shí)例瘾英。所以我們?cè)谑褂肁pplicationContext啟動(dòng)Activity的時(shí)候就會(huì)報(bào)錯(cuò)枣接,因?yàn)榉茿ctivity類的Context沒(méi)有任務(wù)棧。解決辦法就是添加一個(gè)FLAG_ACTIVITY_NEW_TASK
的FLAG
singleTop:棧頂復(fù)用模式方咆。每次啟動(dòng)前看看棧頂是否有當(dāng)前需要啟動(dòng)的Activity的實(shí)例月腋,如果有則不會(huì)創(chuàng)建新的實(shí)例蟀架,而且Activity的onCreate和onStart都不會(huì)被調(diào)用瓣赂,會(huì)在onResume回調(diào)之前回調(diào)一個(gè)onNewIntent的方法榆骚,并且可以從這個(gè)方法的形參中可以取出請(qǐng)求信息。
singleTask:棧內(nèi)復(fù)用模式煌集。只要即將啟動(dòng)的Activity實(shí)例在任何一個(gè)棧內(nèi)存在妓肢,那么該棧會(huì)置于前臺(tái),并且該Activity實(shí)例上所有的Activity會(huì)被移出棧苫纤,同樣會(huì)在onResume之前調(diào)用onNewIntent碉钠。流程如下(假如需要啟動(dòng)Activity A):
singleTask:單實(shí)例模式。就相當(dāng)于加強(qiáng)的singleTask卷拘,但是這個(gè)模式下喊废,這種Activity會(huì)獨(dú)占一個(gè)任務(wù)棧。
注意事項(xiàng)
- 什么是Activity所需的任務(wù)棧栗弟?這個(gè)跟taskAffinity屬性有關(guān)污筷,默認(rèn)情況Activity所需的任務(wù)棧名字和應(yīng)用包名一致。我們可以給每個(gè)Activity單獨(dú)制定這個(gè)參數(shù)乍赫,而且屬性值不能與包名相同瓣蛀,不然就相當(dāng)于沒(méi)有指定。這個(gè)屬性一般和singleTask啟動(dòng)模式或者allowTaskReparenting一起使用雷厂。
-
如何理解taskAffinity為什么需要和singleTask啟動(dòng)模式或者allowTaskReparenting成對(duì)使用惋增?因?yàn)橹付藅askAffinity就相當(dāng)于指定了任務(wù)棧名字,所以只有啟動(dòng)的Activity需要一個(gè)新的任務(wù)棧(啟動(dòng)模式為singleTask或者singleInstance這種就是需要一個(gè)新的任務(wù)棧)才會(huì)起作用改鲫。但是其實(shí)對(duì)于singleInstance诈皿,taskAffinity是不起作用的,加入taskAffinity指定同樣的名稱钩杰,多次啟動(dòng)不同的Activity纫塌,這些Activity的啟動(dòng)模式是singleInstance的話,他們還是會(huì)在不同的任務(wù)棧讲弄。因?yàn)閟ingleInstance會(huì)使一個(gè)Activity獨(dú)占一個(gè)任務(wù)棧措左。同樣,allowTaskReparenting這個(gè)屬性的作用是指定出現(xiàn)符合taskAffinity屬性值的任務(wù)棧是否將Activity從啟動(dòng)它的任務(wù)棧中移至符合的任務(wù)棧中避除,true代表移動(dòng)呕乎,false代表不移動(dòng)。例子:A啟動(dòng)B應(yīng)用中的C這個(gè)Activity:
四篮条,如何給Activity指定啟動(dòng)模式
一是通過(guò)AndroidMenifest種Activity標(biāo)簽下添加launchMode屬性為Activity指定啟動(dòng)模式
二是在實(shí)例化Intent的時(shí)候給它設(shè)置Flag馍驯,例如:
Intent intent = new Intent(this, SecondActivity.class);
intent.addFlag(Intent.FLAG_ACTIVITY_NEW_TASK);
這兩種方法,第二種優(yōu)先級(jí)更高群井。
Flags
FLAG_ACTIVITY_NEW_TASK:為Activity指定“singleTask”啟動(dòng)模式状飞。
FLAG_ACTIVITY_SINGLE_TOP:為Activity指定“singleTop”啟動(dòng)模式。
FLAG_ACTIVITY_CLEAR_TOP:添加此標(biāo)記,啟動(dòng)目標(biāo)Activity時(shí)在同一個(gè)任務(wù)棧中所有位于這個(gè)Activity實(shí)例之上的Activity都要出棧诬辈。這個(gè)一般需要配合FLAG_ACTIVITY_NEW_TASK
一起使用酵使,在這個(gè)情況下如果目標(biāo)Activity已經(jīng)有實(shí)例,那么會(huì)調(diào)用它的onNewIntent焙糟。如果目標(biāo)Activity的啟動(dòng)方式是standard口渔,那么它連同它之上的Activity都會(huì)出棧,然后系統(tǒng)會(huì)創(chuàng)建一個(gè)它的新的實(shí)例放入棧頂穿撮。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有這個(gè)標(biāo)記的Activity不會(huì)出現(xiàn)在歷史Activity的列表中缺脉,等同于在清單文件中Activity標(biāo)簽下指定android:excludeFromRecents="true"
。
五悦穿,IntentFilter的匹配規(guī)則
啟動(dòng)Activity的方式有兩種攻礼,分別是顯式調(diào)用和隱式調(diào)用。
注意:顯式調(diào)用需要明確地指定被啟動(dòng)對(duì)象的組件信息栗柒,包括包名和類名秘蛔,而隱式調(diào)用則不需要明確指定組件信息。原則上一個(gè)Intent不應(yīng)該既是顯式調(diào)用又是隱式調(diào)用傍衡,如果二者共存的話以顯式調(diào)用為主深员。
隱式調(diào)用需要Intent能夠匹配目標(biāo)組件的IntentFilter中所設(shè)置的過(guò)濾信息,如果不匹配將無(wú)法啟動(dòng)目標(biāo)Activity蛙埂。IntentFilter中的過(guò)濾信息有action倦畅、category、data绣的,他們分別可以有多個(gè)叠赐,分別構(gòu)成不同類別的匹配,只有三者同時(shí)匹配上了屡江,才算匹配上了對(duì)應(yīng)的Activity芭概!另外,一個(gè)Activity可以有多個(gè)IntentFilter惩嘉,但是一個(gè)Intent只要能匹配上其中一組就可以了罢洲。
- action的匹配規(guī)則:Intent中的action必須能夠和過(guò)濾規(guī)則中的action的字符串值完全一樣(區(qū)分大小寫),過(guò)濾規(guī)則中action可以有多個(gè)文黎,只要Intent能匹配上一個(gè)就算匹配成功惹苗,但是Intent沒(méi)有action就算匹配失敗。
- category的匹配規(guī)則:Intent中只要有category耸峭,那么Intent中所有的category都必須在過(guò)濾規(guī)則中有就算匹配成功桩蓉。如果Intent沒(méi)有category則也算匹配成功。
注意:系統(tǒng)在調(diào)用startActivity或者startActivityForResult的時(shí)候會(huì)默認(rèn)為Intent加上“android.intent.category.DEFAULT”這個(gè)category劳闹,所以如果過(guò)濾規(guī)則中添加了“android.intent.category.DEFAULT”這個(gè)category院究,我們的Intent不添加category也是可以匹配的
- data匹配規(guī)則:
3.1 data的數(shù)據(jù)分為以下幾種:
android:scheme="string":URI的模式洽瞬,比如http、file业汰、content等片任,如果URI中沒(méi)有指定scheme,那么整個(gè)URI的其他參數(shù)無(wú)效蔬胯,這也意味著URI是無(wú)效的。
android:host="string":URI的主機(jī)名位他,比如www.baidu.com氛濒,如果host未指定,那么整個(gè)URI中的其他參數(shù)無(wú)效鹅髓,這也意味著URI是無(wú)效的舞竿。
android:port="string":URI中的端口號(hào),比如80窿冯,僅當(dāng)URI中指定了scheme和host參數(shù)的時(shí)候port參數(shù)才是有意義的骗奖。
android:path="string":表示完整的路徑信息。
android:pathPattern="string":表示路徑的完整信息醒串,但是可以使用正則表達(dá)式進(jìn)行匹配执桌。
android:pathPrefix="string":表示路徑的前綴信息
android:mimeType="string”:指定媒體類型,例如:“image/*”
主要其實(shí)就是兩大部分芜赌,一是mimeType仰挣,二是uri。uri的組成:<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]缠沈。例如:http://www.baidu.com:80/search/info
3.2 data匹配規(guī)則與action類似膘壶,它要求Intent中必須含有data數(shù)據(jù),并且data數(shù)據(jù)能夠完全匹配Intent-filter中的某一個(gè)data洲愤。
特殊情況說(shuō)明:例如過(guò)濾規(guī)則中指明了mimeType="image/*"颓芭,雖然沒(méi)有指定uri,但是uri是有默認(rèn)值的柬赐,默認(rèn)值的schema為content和file亡问。所以也就是說(shuō)Intent需要額為加上uri,schema必須為content或者file才能匹配肛宋。另外玛界,Intent如果需要同時(shí)指定data和mimeType的話必須調(diào)用setDataAndType方法,不能單獨(dú)調(diào)用setData之后又調(diào)用setType方法悼吱,這會(huì)使得這兩個(gè)屬性相互覆蓋慎框。
過(guò)濾規(guī)則(隱式調(diào)用)總結(jié)
- 隱式調(diào)用下,如果無(wú)法匹配對(duì)應(yīng)的Activity會(huì)報(bào)錯(cuò)后添。同理笨枯,隱式調(diào)用BroadcastReceiver和Service也會(huì)出現(xiàn)類似的錯(cuò)誤。為了避免這種錯(cuò)誤,可以采用PackageManager的resolveActivity方法或者Intent的resolveActivity方法馅精,如果它們找不到匹配的Activity就會(huì)返回null严嗜。
- 另外,PackageManager還提供了queryIntentActivities方法洲敢,這個(gè)方法和resolveActivity方法不同的是:它不是返回最佳匹配的Activity信息而是返回所有成功匹配的Activity信息漫玄。
- queryIntentActivities方法對(duì)比resolveActivity方法,這兩個(gè)方法原型如下:
public abstract List<ResolveInfo> queryIntentActivities(Intent intent,int flags);
public abstract ResolveInfo resolveActivity(Intent intent,int flags);
上面方法中第二個(gè)參數(shù)要使用MATCH_DEFAULT_ONLY這個(gè)標(biāo)志压彭,這個(gè)標(biāo)志的含義是僅僅匹配在過(guò)濾規(guī)則中聲明了<category android:name="android.intent.category.DEFAULT"/>
這個(gè)category的Activity睦优。使用這個(gè)標(biāo)記位的意義在于,只要上述兩個(gè)方法不返回null壮不,那么startActivity一定可以成功汗盘。如果不用這個(gè)標(biāo)記位,就可以把intent-filter中category不含DEFAULT的那些Activity給匹配出來(lái)询一,從而導(dǎo)致startActivity可能失敗隐孽。因?yàn)椴缓蠨EFAULT這個(gè)category的Activity是無(wú)法接收隱式Intent的。
- 在action和category中健蕊,有一類action和category比較重要菱阵,它們是:
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
這二者共同作用是用來(lái)標(biāo)明這是一個(gè)入口Activity并且會(huì)出現(xiàn)在系統(tǒng)的應(yīng)用列表中,少了任何一個(gè)都沒(méi)有實(shí)際意義缩功,也無(wú)法出現(xiàn)在系統(tǒng)的應(yīng)用列表中送粱,也就是二者缺一不可。另外掂之,針對(duì)Service和BroadcastReceiver抗俄,PackageManager同樣提供了類似的方法去獲取成功匹配的組件信息。