启动Activity分为两种,显式调用和隐式调用。显式调用需要明确地指定被启动对象的组件信息,比如包名和类名;隐式调用不需要明确指定组件信息,需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息。
IntentFilter中的过滤信息有action、category、data。一个过滤列表中可以有多个action、category和data可以有多个。一个Intent同时匹配action类别、category类别、data类别才算完全匹配。一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity。
1、action的匹配规则
action是一个字符串,系统预定了一些action,我们也可以在应用中定义自己的action。这里的匹配指的是action的字符串值完全相同。一个过滤规则中可以有多个action,那么Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功。如果Intent中没有指定action,那么匹配失败。另外,action区分大小写。
2、category的匹配规则
category是一个字符串,系统预定了一些category,我们也可以在应用中定义自己的category。Intent可以没有category,如果Intent包含了category,则必须每一个category都能与过滤规则中的category匹配。系统调用startActivity或startActivityResult的时候会默认为Intent加上"android.intent.category.DEFAULT",所以Intent可以没有category。同时,为了我们的Activity能接收隐式调用,就必须在intent-filter中指定"android.intent.category.DEFAULT"。
3、data的匹配规则
data语法如下:
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string"/>
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
实际例子:http://www.baidu.com:80/search/info
scheme:默认值为content或file
path:表示完整路径
pathPattern:包含通配符的完整路径;通配符“*”表示0个或多个任意字符,需要注意的是,由于正则表达式的规范,如果想表示真实的字符串,那么“*”要写成“\\*”,“\”要写成“\\\\”
pathPrefix:表示路径的前缀信息
public Intent setData(Uri data){
mData = data;
mType = null;
return this;
}
判断方法:
1、PackageManager的resolveActivity方法:找不到匹配的Activity,就会返回null
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), mimetype);
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
try {
startActivity(intent);
return;
} catch (ActivityNotFoundException ex) {
if (Config.LOGD) {
Log.d(LOGTAG, "activity not found for " + mimetype
+ " over " + Uri.parse(url).getScheme(), ex);
}
}
2、Intent的resolveActivity方法:找不到匹配的Activity,就会返回null
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:555-2368"));
PackageManager pm = context.getPackageManager();
ComponentName cn = intent.resolveActivity(pm);
if (cn == null) {
Uri marketUri = Uri.parse("market://search?q=pname:com.myapp.packagename");
Intent marketIntent = new Intent(Intent.ACTION_VIEW).setData(marketUri);
if (marketIntent.resolveActivity(pm) != null) {
context.startActivity(marketIntent);
} else {
Log.d(TAG, "Market client not available.");
}
} else{
context.startActivity(intent);
}
PackageManager packageManager = context.getPackageManager();
Intent intent = new Intent(action);
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (resolveInfo.size() > 0) {
return true;
}
return false;
public abstract List<ResolveInfo> queryIntentActivities (Intent intent, int flags)
public abstract ResolveInfo resolveActivity (Intent intent, int flags)
上述两个方法中第二个参数,我们要使用MATCH_DEFAULT_ONLY这个标记位,它的含义仅仅匹配那些在intent-filter中的声明了<category android:name="android.intent.category.DEEFAULT">的Activity。这样就可以避免匹配到不包含DEFAULT这个category的Activity。
intent-filter匹配规则对于Servce和BroadcastReceiver也是同样的道理,PackageManager也提供了类似的方法去获取Service和BroadcastReceivcer组件的匹配信息