Android基础之IntentFilter的匹配规则

1 启动Activity的方式

(1)启动Activity分为两种,显示调用和隐式调用。显示调用需要明确的指定被启动对象的组件信息,包括包名和类名;而隐式意图则不需要明确指定调用信息。原则上一个intent不应该即是显式又是隐式调用,如果二者共存的话以显式调用为主。
(2)隐式调用需要intent能够匹配目标组件的IntentFilter中所设置的过滤信息,一个Activity钟可以有多个intent-filter,一个intent只要能匹配一组intent-filter即可成功启动Activity,如下代码:

<activity android:name=".ShareActivity">
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>
         
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <action android:name="android.intent.action.SEND_MULTIPLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="image/*" />
                <data android:mimeType="text/plain" />
            </intent-filter>
        </activity>

(3)intent到底发给哪个activity,需要进行三个匹配:action、category和data

2 action的匹配规则

(1)action是一个字符串,系统预定了一些actio,同时我们也可以在应用中定义自己的action。
(2)action要求Intent中必须有一个action,且必须和过滤规则中的某一个action相同。另外,action区分大小写,大小写不同的字符串匹配也会失败

3 category的匹配规则

(1)category是一个字符串,系统预定义了一些category,同时我们也可以在应用中定义自己的category。
(2)category要求Intent可以没有category,但是如果一旦有category,不管有几个,每个都要能和过滤规则中的任何一个category相同

<activity
	android:name=".ThirdActivity"
	android:taskAffinity="com.seniorlibs.lifecycle.task1">
           
	<intent-filter>
		<action android:name="com.ryg.charpter_1.c" />
		<action android:name="com.ryg.charpter_1.d" />
		<action android:name="android.intent.action.VIEW" />

		<category android:name="com.ryg.category.c" />
		<category android:name="com.ryg.category.d" />
        <category android:name="android.intent.category.DEFAULT" />
        
		<data android:mimeType="text/plain" />
	</intent-filter>
</activity>

为了匹配前面的过滤规则中的category,可出下面的

①Intent,intent.addcategory (“com.ryg.category.c”);
②或者Intent.addcategory (“com rcategory.d);
③亦或者不设category

(3)为什么不设置category也可以匹配呢?
因为在调用startActivity或者startActivityForResult的时候会默认为Intent加上“android.intent.category.DEFAULT”这个category,所以这个category就可以匹配前面的过滤规则中的第三个category。同时,为了我们的activity能够接收隐式调用,就必须在intent-filter中指定“android intent categor.DEFAULT”这个category,原因刚才已经说明了。

(4)我们定义的activity如果接受隐式intent的话,intent filer就一定要加上android.intent.category.DEFAULT这个category。

(5)学习链接
我们需要什么时候加android.intent.category.DEFAULT呢?

4 data匹配规则

4.1 data的语法

<data
       android:host="string"
       android:mimeType="string"
       android:path="string"
       android:pathPattern="string"
       android:pathPrefix="string"
       android:port="string"
       android:scheme="sstring" />

data由两部分组成,mimeType和URI,前者是媒体类型,比如image/jpeg等,可以表示图片等;而URI包含的数据可就多了,下面的URI的结构:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
// 例子
content://com.seniorlibs.lifecycle:200/folder/subfolder/etc
http://www.baidu.com:80/search/info

(1)Scheme:URI的模式,比如http、file、content等。如果URI中没有指定的scheme,那么整个URI的其他参数无效,这也意味着URI无效。
(2)Host:URI的主机,比如"www.baidu.com"。如果host未指定,那么整个URI中的其他参数无效,这也意味着URI无效。
(3)Port:URI中的端口号,比如80,不过需要指定上面两个才有意义。
(4)Path、pathPattem和pathPrefix:这三个参数表述路径信息,其中path表示完整的路径信息;pathPattern也表示完整的路径信息,但是它里面可以包含通配符“ * ”,“ * ” 表示0个或多个任意字符,需要注意的是,由于正则表达式的规范,如果想表示真实的字符串,那么“* ” 要写成 “ *”,“ \ ”要写成“ \ ”;pathPrefix表示路径的前缀信息。

4.2 匹配规则

data的匹配规则和action类似,它要求Intent中必须含有data数据,并且data数据能够完全匹配过滤规则中的某一个data,这里的完全匹配是指过滤规则中出现的data部分也出现在了Intent中的data中。
(1)如下过滤规则

 <intent-filter>
 		<data android:mimeType="image/*"/>
 </intent-filter>

过滤规则没有指定URI,但是却有默认值,URI的默认值为content何file。也就是说,虽然没有指定URI,但是Intent中的URI部分的scheme必须为content或者file才能匹配,如下:

intent.setDataAndType(Uri.parse("file://abc"),"image/png");

另外,如果要为Intent指定完整的data,必须调用setDataAndType方法,不能县调用setData在调用setType,因为这两个方法彼此会清除对方的值:

// setData会把类型设置为null,同样的,对方也是
public Intent setData(Uri data) {
        mData = data;
        mType = null;
        return this;
}

(2)如下过滤规则

<intent-filter>
    // 指出了完整的属性值,既有URI又有类型
	<data android:mimeType="video/mpeg" android:scheme="http" .../>
	<data android:mimeType="audio/mpeg" android:scheme="http" .../>
</intent-filter>
 intent.setDataAndType(Uri.parse("http://abc"),"video/png");
 // 或者
 intent.setDataAndType(Uri.parse("http://abc"),"audio/png"); 

4.3 data和action不同的地方

// 两个intent-filter作用一样
<intent-filter>
     <data android:scheme="file" android:host="www.baidu.com"/>
 </intent-filter>

 <intent-filter>
       <data android:scheme="file" />
       <data android:host="www.baidu.com"/>
 </intent-filter>

4.4 至此给出完整的intent匹配规则

Intent intent = new Intent();
// Action只能设置一个,重复设置即被替换,Action是"com.ryg.charpter_1.c"
intent.setAction(Intent.ACTION_VIEW);
intent.setAction("com.ryg.charpter_1.c");  

intent.putExtra("time", System.currentTimeMillis());
// Category可以添加多个,但是intent中添加的都必须在规则中匹配。Category包括"com.ryg.category.c"和"android.intent.category.DEFAULT"。
intent.addCategory("com.ryg.category.c");

intent.setDataAndType(Uri.parse("file://abc"), "text/plain");
startActivity(intent);

4.5 备注:通过URL获取参数对应的值

String url = "http://app.cn/index.php/articledesc?id=10943&uid=111&isopen=好好";
//将String类型的地址转变为URI类型
Uri uri = Uri.parse(url); 
//通过URI的getQueryParameter()获取参数值
String id= uri.getQueryParameter("id"); //id 值 10943
String uid= uri.getQueryParameter("uid");//uid 值 111
String isopen= uri.getQueryParameter("isope");//isopen 值 好好

5 启动Activity时匹配隐式Intent

5.1 采用PackageManager的resolveActivity方法(常用)

(1)方法介绍

public abstract List<ResolveInfo>queryIntentActivities(Intent intent,int fladgs);

第二个参数需要注意,要使用MATCH_DEFAULT_ONLY这个标记位,这个标记位的含义是仅仅匹配那些在intentfilter中声明了 < category android-name=”android.intent.category DEFAULT”>这个category的Activity。使用这个标记位的意义在于,只要上述两个方法不返回null,那么startActivity一定可以成功。

如果不用这个标记位,就可以把intent-filter中category不含DEFAULT的那些Activity给匹配出来,从而导致startActivity可能失败。因为不含有DEFAULT这个category的Activity是无法接收隐式Intent的。在action和 category中,有一类action和category比较重要,他们是:

// 共同作用是用来标明这是一个入口Activity并且会出现在系统的应用列表中,
// 少了任何一个都没有实际意义,也无法出现在系统的应用列表中
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />

(2)模板例子

// 浏览器
public static final int THIRD_ACTIVITY_BROWSABLE = 1;
// 微信
public static final int THIRD_ACTIVITY_WEIXIN = 2;
 
 /**
     * 跳转第三方应用
     * 通过隐式Intent的跳转,在发出Intent之前必须通过resolveActivity检查,避免找不到合适的调用组件,造成ActivityNotFoundException的异常
     *
     * @param context
     * @param url
     */
    public static boolean openThirdActivity(Context context, String url, int name) {
        if (context == null || TextUtils.isEmpty(url)) {
            return false;
        }

        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        if (name == THIRD_ACTIVITY_BROWSABLE) {
            intent.addCategory(Intent.CATEGORY_BROWSABLE);
        }
        if (context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
            try {
                context.startActivity(intent);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            if (name == THIRD_ACTIVITY_BROWSABLE) {
                ToastUtils.showToast(context, "浏览器未安装"));
            } else if (name == THIRD_ACTIVITY_WEIXIN) {
                ToastUtils.showToast(context, "微信未安装"));
            }
        }

        return false;
    }
// 1、外部浏览器
ActivityUtils.openThirdActivity(activity, deploy.onClickUrl, ActivityUtils.THIRD_ACTIVITY_BROWSABLE);
// 2、外部调起微信url前缀
ActivityUtils.openThirdActivity(context, "weixin://", ActivityUtils.THIRD_ACTIVITY_WEIXIN);
// 2、微信
ActivityUtils.openThirdActivity(UCActivity.this, "weixin://", ActivityUtils.THIRD_ACTIVITY_WEIXIN);

5.2 Intent的resolveActivity方法

5.3 PackageManager的queryIntentActivities方法

它不是返回最佳匹配的Activity信息而是返回所有成功匹配的Activity信息,

public abstract List<ResolveInfo>queryIntentActivities(Intent intent,int fladgs);

6 学习博客

Android开发艺术探索笔记——第一章:Activity的生命周期和启动模式

发布了185 篇原创文章 · 获赞 207 · 访问量 59万+

猜你喜欢

转载自blog.csdn.net/chenliguan/article/details/87927588