我們知道,Activity的啟動模式分為兩種,分別是顯式啟動和隱式啟動。顯式啟動需要明確的指定被啟動的對象的組件信息,包括包名和類名;而隱式啟動需要 Intent 能夠匹配目標組件的 IntentFilter 中所設置的過濾信息(原則上,一個Intent不應該既是顯式調用又是隱式調用,如果二者共存,則顯示調用為主)。
IntentFilter 中的過濾信息包括 action、category 和 data。為了匹配過濾列表,需要同時匹配過濾列表中的action、category和data信息,否則匹配失敗。一個Activity中可以有多個IntentFilter,一個Intent只要能匹配任何一組 intent-filter,即可成功啟動對應的Activity。以下是一個過濾規則的實例:
<activity android:name="ShareActivity"> <intent-filter> <action android:name="my.itgungnir.action1" /> <category android:name="my.itgungnir.category1" /> <data android:mimeType="text/plain" /> </intent-filter> <intent-filter> <action android:name="my.itgungnir.action2" /> <action android:name="my.itgungnir.action3" /> <category android:name="my.itgungnir.category2" /> <category android:name="my.itgungnir.category3" /> <category android:name="my.itgungnir.category4" /> <data android:mimeType="text/plain" /> <data android:host="www.baidu.com" /> </intent-filter> </activity>
action的匹配規則
action是一個字符串。action的匹配規則是:Intent中必須有一個action且必須能夠和過濾規則中的某個action匹配(這里說的匹配是指字符串值完全一樣)。
【注意】
-
- action中的內容是區分大小寫的;
- Intent中如果沒有指定action,則視為匹配失敗。
category的匹配規則
category是一個字符串。category的匹配規則是:Intent中可以沒有category,但是如果一旦有category,不管有幾個,每個都要能夠和過濾規則中的任何一個category匹配。
【注意】:如果想讓Activity A隱式啟動Activity B,那么需要在Activity B的 intent-filter 中指定 android.intent.category.DEFAULT 這個category,原因是系統在調用 startActivity() 或者 startActivityForResult() 方法的時候會默認為Intent加上 android.intent.category.DEFAULT 這個category。
data的匹配規則
data的匹配規則:Intent中必須含有data數據,並且data數據能夠完全匹配過濾規則中的某一個data。
先來看 data 的語法格式:
<data android:scheme="string" android:host="string" android:port="string" android:path="string" android:pathPattern="string" android:pathPrefix="string" android:mimeType="string" />
data由兩部分組成: mimeType 和 URI ,URI通過如下格式,包括scheme、host、port、path、pathPrefix和pathPattern。
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
具體的參數解釋如下:
mimeType :指媒體類型,比如 image/jpeg、audio/mpeg4-generic、vidio/*等,可以表示圖片、文本、視頻等不同的媒體格式。
scheme :URI的模式,如http、file、content等,如果URI中沒有指定scheme,那么整個URI的其他參數無效,這也意味着URI是無效的。
host :URI的主機名,如www.baidu.com,如果host未指定,那么整個URI中的其他參數無效,這也意味着URI是無效的。
port :URI中的端口號,比如80,進檔URI中指定了scheme和host參數的時候,port參數才是有意義的。
path :表述路徑的完整信息。
pathPrefix :表述路徑的前綴信息。
pathPattern :表述路徑的完整信息,但它里面可以包含通配符 * ,表示0個或任意字符(如果想要表示真是字符串,則需要轉義成 \\* ; \ 要寫成 \\\\ )。
我們可以通過 intent.setDataAndType(Uri.parse("URI字符串"), "mimeType字符串") 的格式為Intent設置data。
【注意】
-
- URI可以不設置,但如果設置了,則 scheme 和 host 屬性必須要設置;
- URI的 scheme 屬性有默認值,默認值為 content 或者 file ,因此,就算在 intent-filter 中沒有為data設置URI,也需要在匹配的時候設置scheme和host兩個屬性,且scheme屬性的值必須是content或者file;
- 在為Intent指定data的時候,必須要調用 setDataAndType() 方法,不能先調用 setData() 再調用 setType() ,因為這兩個方法會彼此清楚對方的值;
- 所有有關data的屬性可以放在同一個<data>標簽中,也可以分作多個<data>標簽存放,其效果相同。
總結
1、以下是在JAVA代碼中匹配某個Activity的 intent-filter 的代碼:
Intent intent = new Intent(); intent.addAction("my.itgungnir.action1"); intent.addCategory("my.itgungnir.category1"); intent.setDataAndType(Uri.parse("file://abc"), "text/plain"); startActivity(intent);
2、在Menifest文件的<intent-filter>標簽中,action、category和data都可以有多個;在JAVA代碼中,一個Intent中只能有一個action和一個data,可以有多個category。
3、我們在通過隱式方式啟動一個Activity的時候,可以做以下判斷,看有沒有Activity能夠匹配我們的Intent,具體的判斷方法有兩種:
(1)使用 PackageManager 或者 Intent 的 resolveActivity() 方法,這個方法會返回最佳匹配的Activity信息,如果沒有匹配的Activity,則返回null;
(2)使用 PackageManager 的 queryIntentActivities() 方法,這個方法會返回所有成功匹配的Activity的信息。
public abstract ResolveInfo resolveActivity(Intent intent, int flags); public abstract List<ResolveInfo> queryIntentActivities(Intent intent, int flags);
需要說明的是這兩個方法的第二個參數,我們在使用這兩個方法的時候,第二個參數都必須是 Intent.MATCH_DEFAULT_ONLY ,這個參數用來匹配那些在 intent-filter 中聲明了category為 android.intent.category.DEFAULT 的Activity,避免某些Activity因為沒有設置category為DEFAULT而無法接收隱式Intent。
4、如果想將一個Activity標記為應用的入口,可以在其 <intent-filter> 標簽中添加如下兩行屬性(這兩行屬性必須同時存在才有用,缺一不可):
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />