Android讀書筆記(1)—— Activity的生命周期和啟動(dòng)模式

一、Activity的生命周期全面分析

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

1、典型情況下的生命周期分析

Activity生命周期
  • 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ì)銷毀重建。生命周期如下

異常情況下Activity的重建過(guò)程

當(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ù)探索》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容