待學(xué)的
- 任務(wù)棧
Activity的 lauchMode
在android系統(tǒng)默認(rèn)狀態(tài)下瘫俊,當(dāng)我們啟動(dòng)activity的時(shí)候,系統(tǒng)會(huì)創(chuàng)建多個(gè)實(shí)例烁巫,并把它們放到一個(gè)任務(wù)棧中巢寡,當(dāng)我們回退的時(shí)候,這些Activity 會(huì)一一回退夸楣。 任務(wù)棧是一個(gè)“先進(jìn)后出”的站結(jié)構(gòu)宾抓,當(dāng)棧中內(nèi)容為空的時(shí)候,系統(tǒng)會(huì)回收這個(gè)任務(wù)棧裕偿。 在創(chuàng)建 activity 的時(shí)候洞慎,有四種啟動(dòng)方式,下面以一一列舉:
standard 標(biāo)準(zhǔn)的啟動(dòng)模式嘿棘,也系統(tǒng)默認(rèn)啟動(dòng)模式劲腿。 每次啟動(dòng)都會(huì)重建一個(gè)新的實(shí)例。它的 onCreate鸟妙、 onStart焦人、onResume 都會(huì)被調(diào)用。
一個(gè)任務(wù)椫馗福可以有多個(gè)實(shí)例花椭,每個(gè)實(shí)例可以屬于不同的任務(wù)棧。 在這種模式下房午,誰啟動(dòng)了這個(gè)activity矿辽,那么這個(gè)activity就運(yùn)行在誰的任務(wù)棧中。
當(dāng)使用 ApplicationContext 去啟動(dòng) standard 模式的activity時(shí)候,會(huì)報(bào)錯(cuò)袋倔;
這是因?yàn)榉?activity 類型的 context 并沒有所謂的任務(wù)棧雕蔽,所以會(huì)出現(xiàn)問題。解決方法就是為待啟動(dòng)的activity指定 FLAG_ACTIVITY_NEW_TASK 標(biāo)記位宾娜,這樣啟動(dòng)的時(shí)候就會(huì)新建一個(gè)任務(wù)棧批狐,這時(shí)候,實(shí)際以 singleTask 模式啟動(dòng)的前塔。singleTop 棧頂復(fù)用模式嚣艇。這種模式下,如果該 Activity 已經(jīng)有實(shí)例位于棧頂华弓, 那么該 activity 的實(shí)例不會(huì)被重新重建食零,同時(shí)它的 onNewIntent 方法會(huì)被回調(diào),但是 onCreate该抒、onStart 等不會(huì)被調(diào)用慌洪。
singleTask 棧內(nèi)復(fù)用模式。這是一種單例模式凑保,在這種模式下,只要棧存在于需要的任務(wù)棧中涌攻,多次調(diào)用都不會(huì)重新創(chuàng)建實(shí)例欧引, 系統(tǒng)也會(huì)回調(diào) OnNewIntent。
具體說:當(dāng)一個(gè)具有 singleTask 模式的activity A請(qǐng)求啟動(dòng)后恳谎, 系統(tǒng)首先會(huì)尋找是否存在 A 想要的任務(wù)棧芝此, 如果不存在,就新建一個(gè)任務(wù)棧因痛,然后創(chuàng)建 A的實(shí)例后放入棧中婚苹。 如果A所需的任務(wù)棧存在,這時(shí)要看A是否在棧中有實(shí)例存在鸵膏, 如果有實(shí)例存在膊升,系統(tǒng)會(huì)把A調(diào)到棧頂并調(diào)用它的 onNewIntent, 如果實(shí)例不存在谭企,就創(chuàng)建A的實(shí)例廓译,并壓入棧中。
singleTask 默認(rèn)具有 clearTop 的效果债查, 會(huì)導(dǎo)致已存在的實(shí)例之上的activity全部出棧非区。
- singleInstance 單實(shí)例模式,這是一種加強(qiáng)的 singleTask 模式盹廷,它除了具有 singleTask 模式的所有特性以外征绸, 還加強(qiáng)了一點(diǎn),那就是具有此種模式的 activity 只能單獨(dú)地位于一個(gè)棧中。比如 Activity A是singleInstance 模式管怠, 當(dāng)A啟動(dòng)以后剥汤,系統(tǒng)會(huì)為它創(chuàng)建一個(gè)新的任務(wù)棧,然后 A 獨(dú)自存在在這個(gè)新的任務(wù)棧中排惨,由于棧內(nèi)復(fù)用的特點(diǎn)吭敢, 后續(xù)均不會(huì)創(chuàng)建新的實(shí)例,除非這個(gè)獨(dú)特的任務(wù)棧被系統(tǒng)銷毀了暮芭。
幾個(gè)問題
問題1: 文中提到的某個(gè) activity所需的任務(wù)棧鹿驼, 什么是 activity 所需要的任務(wù)棧呢?
這要從一個(gè)參數(shù)說起: TaskAffinity 翻譯為任務(wù)相關(guān)性辕宏。這個(gè)參數(shù)標(biāo)識(shí)了一個(gè) activity 所需要的任務(wù)棧的名字畜晰,默認(rèn)情況下,所有 activity 所需的任務(wù)棧的名字為應(yīng)用的包名瑞筐。 當(dāng)然我們可以為每個(gè) activity 單獨(dú)指定 taskaffinity 屬性凄鼻,這個(gè)屬性要和包名不同, 否則相當(dāng)于沒指定聚假。
TaskAffinity 屬性主要和 singleTask 或者 allowTaskReparenting 屬性配對(duì)使用块蚌,其他情況下沒意義。
當(dāng)TaskAffinity和singleTask啟動(dòng)模式配對(duì)使用的時(shí)候膘格, 他是具有該模式的 Activity 的目前任務(wù)棧的名字峭范,待啟動(dòng)的 activity 會(huì)運(yùn)行在名字和 taskAffinity 名字相同的任務(wù)棧中。
問題2 什么情況下 TaskAffinity 會(huì)生效瘪贱?
只有Activity設(shè)置了 lauchMode = "singleTask" 或者 allowTaskReparenting 才起作用
Activity 的 Flags
Activity 的標(biāo)記位有很多纱控,列舉一些常用的標(biāo)記位。標(biāo)記位有多種作用菜秦√鸷Γ可以設(shè)定Activity的啟動(dòng)模式,也可以影響 activity 的運(yùn)行狀態(tài)球昨。
影響啟動(dòng)模式的:
- FLAG_ACTIVITY_NEW_TASK 等同于xml設(shè)置 "singleTask"啟動(dòng)模式
- FLAG_ACTIVITY_SINGLE_TOP 等同于 xml 中設(shè)置 "singleTop"啟動(dòng)模式
影響運(yùn)行狀態(tài)的:
- FLAG_ACTIVITY_CLEAR_TOP 如果啟動(dòng)模式為 "singleTask"尔店,且該activity已存在,則清除棧中該activity之上的褪尝,只調(diào)用 onNewIntent() 闹获,不重新啟動(dòng)。
如果啟動(dòng)模式為 “standard”河哑,那么它連同它之上的都要出棧避诽,系統(tǒng)會(huì)創(chuàng)建新的 activity并放入棧頂。 - FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 具有這個(gè)標(biāo)記的不會(huì)出現(xiàn)在歷史 activity 列表中璃谨,相當(dāng)于在 xml 中設(shè)置屬性 android:excludeFromRecents="true"
IntentFilter 的匹配規(guī)則
啟動(dòng) Activity 有兩種方式沙庐,顯式啟動(dòng)和隱式啟動(dòng)鲤妥。
顯式啟動(dòng)要指定被啟動(dòng)的組件信息,比較簡(jiǎn)單具體不談拱雏。
隱式啟動(dòng)則需要 intent 能夠匹配目標(biāo)組件的 IntentFilter 中所設(shè)置的過濾信息棉安。
IntentFilter 中的過濾信息有 action、category铸抑、data 三個(gè)類別贡耽,給了匹配過濾列表需要同時(shí)匹配列表中的 action, category, data信息。一個(gè)activity可以有多個(gè) IntentFilter, 一個(gè)intent只要能匹配其中一組 intentFilter 就可以啟動(dòng)對(duì)應(yīng)的 activity鹊汛。
- action 的匹配規(guī)則
action 是一個(gè)字符串蒲赂,一個(gè)intent一般只攜帶一個(gè)action。如果攜帶多個(gè)action刁憋,則都要在 IntentFilter中包含才能正常啟動(dòng)滥嘴,但如果 Intent 中沒有指定 action 則匹配失敗。 匹配時(shí)嚴(yán)格區(qū)分大小寫至耻。 intent.setAction("..........")
- category 的匹配規(guī)則
category 是一個(gè)字符串若皱。 如果 intent 中攜帶 category,不管攜帶幾個(gè)尘颓,都要在 IntentFilter 中找到相匹配的才能啟動(dòng)走触,若不攜帶, 系統(tǒng)會(huì)默認(rèn)設(shè)置 "android.intent.category.DEFAULT"這個(gè) category泥耀,所以在 IntentFilter 中至少要設(shè)置 <category android:name="android.intent.category.DEFAULT"/> 這一個(gè)配置項(xiàng)饺汹。否則啟動(dòng)失敗。
- data 的匹配規(guī)則
data 的匹配規(guī)則和 action 類似, 但是 data 要復(fù)雜的多痰催,先了解一下data 的結(jié)構(gòu) :
<data android:scheme="String"
android:host="String"
android:port="String"
android:path="String"
android:pathPattern="String"
android:pathPrefix="String"
android:mimeType="String"/>
data由兩部分組成: mimeType 和 URL.
mimeType 指媒體類型,如 text/plain,image/jpeg, audio/mpeg4-generic 和 video/* 等迎瞧,可以表示 文本夸溶,圖像,音頻凶硅,視頻等不同的媒體格式缝裁。
URL 包含的數(shù)據(jù)略多, 下面是 URL 的結(jié)構(gòu):
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
例子:
content://com.example.project:200/floder/subfloder/etc
http://www.baidu.com:80/search/info
每個(gè)數(shù)據(jù)的含義:
scheme: URL的模式足绅,如 http, file, content 等捷绑,如果URL中沒有指定 scheme,那么整個(gè) URL 的其他參數(shù)無效氢妈,也就意味著URL無效粹污。
Host: URL的主機(jī)名,比如 www.baidu.com, 如果 host 未指定首量,則其他參數(shù)無效壮吩,URL也無效进苍。
Port : 端口號(hào), 只有指定了 scheme 和 host 時(shí)候鸭叙, port 才有意義觉啊。
Path, PathPrefix, PathPattern: 這三個(gè)參數(shù)表述路徑信息,其中 path 表示完整的路徑信息沈贝;pathPattern
示例1:
<intent-filter>
<data android:mimeType=" image/* " />
......
</intent-filter>
這種規(guī)則制定了媒體類型為照片杠人,那么intent中的mimeType為“ image/* ”才能匹配,這種情況下沒有指定URL, 但是有默認(rèn)值宋下, 默認(rèn)值是 content 和 file嗡善, 也就是說,雖然沒有指定 URL杨凑,但是 intent 中的URL部分的 scheme 必須為 content 或者 file 才能匹配滤奈。
另外,想要為 Intent 指定完整的data撩满,必須要使用 inent.setDataAndType, 不能先使用 setData 后使用 setType ,這樣會(huì)清除對(duì)方的置蜒程。
實(shí)例2:
<intent-filter>
<data android scheme="http" .... android:mimeType=" video/mpeg " />
<data android scheme="http" .... android:mimeType=" audio/mpeg " />
......
</intent-filter>
這種規(guī)則指定了兩組 data, 為了匹配實(shí)例2的規(guī)則伺帘,正確的 intent 應(yīng)該如下:
intent.setDataAndType(Url.parse("http://abc"), "video/mpeg");
或者是
intent.setDataAndType(Url.parse("http://abc"), "audio/mpeg");
最后昭躺, 如果,匹配不到合適的 activity 怎么辦伪嫁?只能奔潰么领炫?
當(dāng)我們隱式啟動(dòng)一個(gè) Activity 的時(shí)候商架,可以做一下判斷皿淋,看是否能夠匹配我們的 Intent 。方法有兩種, 都在 Context 中:
public abstract List<ResolveInfo> getPackageManager().queryIntentActivities(Intent intent做修,int flag)
或者
public abstract ResolveInfo getPackageManager().resolveActivity(Intent intent脚猾,int flag);
上述兩個(gè)方法葱峡,第一個(gè)參數(shù)沒什么好說的, 第二個(gè)參數(shù)龙助,我們要使用 PackageManager.MATCH_DEFAULT_ONLY 這個(gè)標(biāo)記砰奕, 這個(gè)標(biāo)記的含義是僅僅匹配那些在 intent-filter 中聲明了 <category android:name="android.intent.category.DEFAULT"> 這個(gè) Catrgory 的 activity, 是要返回不為null提鸟, 那么就有匹配到的activity军援, 就一定能隱式啟動(dòng)成功。因?yàn)椴缓?DEFAULT 這個(gè)category 的activity 是無法接受隱式intent的称勋。
在匹配規(guī)則中胸哥, 有一類 action 和 category 比較重要,那就是:
<action android:name="anroid.intent.action.MAIN"/>
<categoty android:name="android.intent.category.LAUCHER"/>
這兩者公共來表明一個(gè)入口 activity铣缠,并且會(huì)出現(xiàn)在Home Launcher上烘嘱。少了任何一個(gè)都不行昆禽。如果在 Intent-Filter 中還有data選項(xiàng), 則不匹配限制條件蝇庭,不能出現(xiàn)在 Home Laucher上醉鳖。 如下面這種 intent-filter:
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="urlscheme"
android:host="auth_activity">
</intent-filter>
</activity>
針對(duì) service 和 BroadcastReceiver ,PacketManager 同樣提供了類似的方法去獲取成功匹配的組件信息哮内。