前言
參考書:Android 開發(fā)藝術(shù)探索
本篇主要介紹 Activity 的生命周期、啟動模式和 Intentfliter 的匹配規(guī)則
正文
一、Activity 的生命周期
分兩種: 正常情況下和異常情況下的生命周期
1.1 正常情況下的生命周期,從上到下
onCreate(): 表示 Activity 正在創(chuàng)建,可以做一些初始化工作。
onStart(): 表示 Activity 正在啟動,這時 Acticity 已經(jīng)創(chuàng)建出來了,只是沒有出現(xiàn)在前臺,用戶看不到
onResume(): 表示 Activity 已經(jīng)可見,可以與用戶進(jìn)行交互
onPause(): 表示 Acticity 正在停止,此時可以做一些停止動畫、存儲數(shù)據(jù)等操作,但是注意不能耗時,因?yàn)橹挥羞@個方法執(zhí)行完畢,新的 Activity 的 onResume 才會執(zhí)行
onStop(): 表示 Activity 即將停止,可以做一些重量級的回收工作,但是不能耗時
onDestroy(): 表示 Activity 即將被銷毀,可以做一些回收工作和資源釋放
還有一個 onRestart() 方法,此方法表示 Activity 正在重新啟動,一般情況下在 Activity 從不可見到可見狀態(tài)的時候,會調(diào)用此方法,比如說 A 跳轉(zhuǎn)到 B 然后再返回 A
1.2 異常情況下的生命周期
1.2.1 資源相關(guān)的系統(tǒng)配置發(fā)生改變導(dǎo)致 Activity 被殺死并重新創(chuàng)建
比如說,橫豎屏切換的時候,顯示的圖片資源及布局文件等系統(tǒng)配置發(fā)生改變,默認(rèn)情況下,Activity 會被銷毀并重新創(chuàng)建,其生命周期方法如下:
首先會調(diào)用 onSaveInstanceState() 方法,做數(shù)據(jù)保存工作,系統(tǒng)默認(rèn)為我們保存當(dāng)前 Activity 的視圖結(jié)構(gòu),并在 Activity 重啟后,為我們恢復(fù)這些數(shù)據(jù),比如 文本框中用戶輸入的數(shù)據(jù),ListView 滾動的位置等,但是如果針對于某個 View 來說,能恢復(fù)什么數(shù)據(jù),可以看 View 的源碼來分析,因?yàn)?View 和 Activity 一樣,都有 onSaveInstanceState() 方法來保存數(shù)據(jù),保存的數(shù)據(jù)在其參數(shù) Bundle 中
其次,調(diào)用 onPause() 、onStop()、onDestory() 方法,注意 onSaveInstanceState() 方法可能在 onPause() 之前調(diào)用,也可能在其之后調(diào)用。
然后,調(diào)用 onCreat() 方法,然后繼續(xù)調(diào)用 onRestoreInstanceState() 方法來為其恢復(fù)狀態(tài)和數(shù)據(jù),我們可以根據(jù)這兩個方法中的參數(shù) Bundle 來判斷此 Activity 是否被重建
1.2.2 資源內(nèi)存不足,導(dǎo)致低優(yōu)先級的 Activity 被殺死
這種方式與上邊的第一種情況保存和恢復(fù)數(shù)據(jù)的方法一致,這里說下 Activity 的優(yōu)先級,從高到低,如下所示:
前臺 Activity ,正在與用戶交互,優(yōu)先級最高
可見,但并非前臺 Activity ,比如 Activity 中彈出一個對話框,導(dǎo)致 Activity 可見,但是無法與用戶交互
后臺 Activity ,已經(jīng)被暫停的 Activity ,比如執(zhí)行了 onStop() 方法,優(yōu)先級最低
另外注意,如果一個進(jìn)程中沒有四大組件運(yùn)行,那么這個進(jìn)程將會很快被殺死!
1.2.3 阻止 Activity 重新創(chuàng)建
在 AndroidMenifest.xml 中為 Activity 添加一條 configChanges 屬性 :
android:configChanges="orientation"
常用屬性值的含義:
locale :設(shè)備的本地位置發(fā)生了改變,一般指切換了系統(tǒng)語言
orientation :設(shè)備屏幕發(fā)生改變,比如旋轉(zhuǎn)屏幕
keyboardHidden :鍵盤的可訪問性發(fā)生了改變,比如用戶調(diào)出了鍵盤
screenSize :屏幕尺寸信息發(fā)生改變,常用于旋轉(zhuǎn)屏幕導(dǎo)致的 尺寸信息改變,一般和 orientation 配合使用
smallestScreenSize :表示設(shè)備的物理屏幕尺寸發(fā)生改變,注意指的是物理設(shè)備,跟旋轉(zhuǎn)屏幕沒關(guān)系,比如用戶切換到了外部的顯示設(shè)備,這個不常用。
二、Activity 的啟動模式
2.1 四種啟動模式
standard :標(biāo)準(zhǔn)模式,也是系統(tǒng)的默認(rèn)模式,每次啟動一個 Activity 都會創(chuàng)建一個新實(shí)例,不管這個實(shí)例是否存在,會一一放入任務(wù)棧中,然后按回退鍵的時候,會按照先進(jìn)后出的原則,一一退棧!
singleTop :棧頂復(fù)用模式,如果新創(chuàng)建的 Activity 已經(jīng)位于任務(wù)棧的棧頂了,那么此 Activity 不會被重建,注意這個 Activity 的 onCreat()、onstart() 方法不會被調(diào)用,因?yàn)樗]有發(fā)生改變,但是會回調(diào) onNewIntent(Intent intent) 方法,從而獲取 intent 信息。
singleTask :棧內(nèi)復(fù)用模式,這是一種單實(shí)例模式,只要 Activity 在一個棧中存在,那么多次啟動 Activity 都不會重新創(chuàng)建實(shí)例,和 singleTop 一樣,也會回調(diào)其 onNewIntent(Intent intent) 方法,但是需要注意一點(diǎn),如果棧中有的話,該模式,會把所需要的 Activity 之上的所有 Activity 彈出棧,將需要的這個 Activity 放于棧頂!
singleInstance : 它是一種加強(qiáng)版的 singleTask ,它除了具有 singleTask 的所有特性之外,還加強(qiáng)了一點(diǎn),就是只能單獨(dú)的位于一個棧中!一個棧只能有一個 Activity
2.2 為 Activity 指定啟動模式
- 第一種,通過 AndroidMenifest.xml 文件中,為其添加屬性
android:launchMode="singleTop"
- 第二種,通過在 Intent 中設(shè)置標(biāo)志位 Flags 來為 Activity 指定模式
Intent intent = new Intent(this,TextActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
- 兩種方式的區(qū)別:
- 優(yōu)先級,第二種要高于第一種,兩種都存在的話,以第二種為準(zhǔn);
- 限定范圍不同,第一種無法為 Activity 指定 FLAG_ACTIVITY_CLEAR_TOP 標(biāo)識,第二種無法為 Activity 指定 singleInstance 模式!
2.3 Activity 的 Flags
Activity 的 Flags 有很多,作用也很多,有些可以設(shè)定 Activity 的啟動模式,有些可以影響 Acticity 的運(yùn)行狀態(tài),這里記錄些比較常用的 Flags
FLAG_ACTIVITY_NEW_TASK ,指定 Activity 的啟動模式為 singleTask
FLAG_ACTIVITY_SINGLE_TOP ,指定 Activity 的啟動模式為 singleTop
FLAG_ACTIVITY_CLEAR_TOP ,當(dāng) Activity 啟動時,與其在同一個任務(wù)棧并在其上邊的所有 Activity 全部出棧,一般和 singleTask 啟動模式一塊出現(xiàn)
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS ,在某些情況下,我們不希望用戶通過歷史列表回到我們的 Activity 的時候,使用這個標(biāo)記,等同于 xml 文件中的屬性: android:excludeFromRecents="true"
三、Activity 中 IntentFilter 匹配規(guī)則
Activity 的啟動方式有兩種,顯式啟動和隱式啟動,如果兩者都存在那么以顯示為主,顯式啟動很簡單,主要記錄下隱式啟動
隱式啟動需要 Intent 能夠匹配目標(biāo)組件的 IntentFilter 中的過濾信息,過濾信息有三個,分別是 action 、 category 、 data,下邊針對這三個過濾信息做介紹
3.1 action 的匹配規(guī)則
- action 只是一個字符串,區(qū)分大小寫,系統(tǒng)中有預(yù)定義的一些 action 我們也可以自定義自己所需要的 action, action 可以有多個,但是我們只要匹配成功一個即可匹配成功,需要注意的是,只要是隱式啟動,那么 Intent 中必須要有 action
3.2 category 的匹配規(guī)則
- category 也是一個字符串,category 也可以有多個,但是必須要每個都匹配成功才行,另外,如果需要隱式啟動,那么必須添加 android.intent.category.DEFAULT 這個 category ,因?yàn)槲覀冋{(diào)用 startActivity 方法的時候,系統(tǒng)會默認(rèn)為我們添加這個一個 category ,所以必須要添加
3.3 data 的匹配規(guī)則
- data 相對復(fù)雜一點(diǎn),結(jié)構(gòu)如下
<data android:scheme="aaa"
android:host="aaa"
android:port="aaa"
android:path="aaa"
android:pathPattern="aaa"
android:pathPrefix="aaa"
android:mimeType="aaa"/>
主要是有兩部分組成 mimeType 和 Uri
- mimeType 指媒體類型 例如: image/jpeg vided/* ...
- Uri 的結(jié)構(gòu)如下:
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
Uri 的屬性介紹如下:
scheme:整個URI的模式,如常見的http,file等,注意如果URI中沒有指定的scheme,那么整個uri無效
host:URI的域名,比如我們常見的www.mi.com,www.baidu.com,與scheme一樣,一旦沒有host那么整個URI也毫無意義;
port:端口號,比如80,很容易理解,只有在URI中指定了scheme和host之后端口號才是有意義的;
path,pathPattern,pathPrefix包含路徑信息,path表示完整的路徑,pathPattern在此基礎(chǔ)上可以包含通配符,pathPrefix表示路徑的前綴信息;
- 只匹配 scheme 的例子如下:
<activity android:name=".TextActivity">
<intent-filter>
<action android:name="111"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<data android:scheme="222"></data>
</intent-filter>
</activity>
Intent intent = new Intent();
intent.setAction("111");
// scheme:// 固定寫法,后邊的 111 是自己隨便寫的
intent.setData(Uri.parse("222://111"));
startActivity(intent);
- 只匹配 mimeType 的例子如下
<activity android:name=".TextActivity">
<intent-filter>
<action android:name="111"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<data android:mimeType="image/*"></data>
</intent-filter>
</activity>
Intent intent = new Intent();
intent.setAction("111");
// 這種情況,scheme 默認(rèn)為 content ,親測 file 會報錯
//注意此處是 setDataAndType
intent.setDataAndType(Uri.parse("content://111"),"image/png");
startActivity(intent);
- 注意,data,不是必須要添加的,也就是說如果只有 action 和 category 也能匹配成功
還有一點(diǎn),如果我們要啟動系統(tǒng)的頁面,如打電話頁面,需要找到其匹配規(guī)則,進(jìn)行匹配,然后啟動
另外,IntentFilter 可以有多對,只要匹配其中一對即可成功。