安卓IntentFilter的匹配规则

IntentFilter的匹配规则

安卓使用隐式调用时,需要Intent能够匹配目标组件的IntentFilter中设置的过滤信息,如果不匹配将无法启动目标Activity,IntentFilter中的过滤信息有action、category、data。

  • 一个Activity中可以有多个intent-filter,只要intent能够匹配中其中一组就能够启动Activity
  • 只有一个Intent能够同时匹配action类别,category类别,data类别才能算完全匹配

1.action的匹配规则

action是一个字符串(区分大小写),acion的匹配规则是Intent中的action必须能够和过滤规则中的action匹配(字符串内容完全相等),一个过滤规则中可以有多个action,只要intent中的action能够和过滤规则中的任何一个action相同就能匹配成功。如果匹配失败,抛出异常android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.custom }

  • 隐式启动
	<activity
        android:name=".MainActivity2"
        android:exported="false">
        <intent-filter>
        	<!--这里有两个action-->
            <action android:name="android.intent.action.custom"/>
			<action android:name="android.intent.action.west"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>
        findViewById<TextView>(R.id.tvHello).setOnClickListener {
            Intent().also {
                it.action = "android.intent.action.custom"
                startActivity(it)
            }
        }

结果:启动成功,证明action只需要匹配其中一个即可。

2.category的匹配规则

cagegory是一个字符串,它的匹配规则是,如果一个intent中含有category,那么AndroidManifest.xml中定义的所有的category都必须和过滤规则中的每一个category相同。
为什么上面的例子中,不设置category也能够匹配成功呢?因为系统在调用startActivity时会默认加上andoid.intent.category.DEFAULT,所以在AndroifManifest.xml中也需要加上andoid.intent.category.DEFAULT,否则也无法匹配。

3.data的匹配规则

与action类似,能命中intent-filter中data的其中一组,就可以打开activity
data的语法结构:

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

data由两部分组成:miniType和URI,miniType指媒体类型,比如image/jpeg、video/*等
URI结构:😕/:/[ ||]
URI例子:http://www.baidu.com:80/search/info

  • Scheme:URI的模式,比如http、file、content等,如果URI中没有指定scheme,那么整个URI的其他参数将无效,意味着URI也无效。
  • Host:URI的主机名,比如www.baidu.com,如果host未指定,那么整个URI中的其他参数无效,意味着URI也是无效的。
  • Port:URI的端口号,仅当URI中指定了scheme和host参数的时候,port才是有意义的。
  • Path、pathPattern和pathPrefix:这三个参数表述路径的信息,其中path表示完整的路径信息,pathPattern也表示完整的路径信息,但是它里面可以包含通配符“”,“”表示0个或多个任意字符(由于正则表达式的规范,如果想表示真实的字符串,那么“”要写成“\”,“\”要写成"\\",pathPattern表示路径的前缀信息)
  • data匹配例子
	<intent-filter>
    	<action android:name="android.intent.action.west"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data 
        	android:scheme="west"
            android:host="com.example.west"
			android:mimeType="image/jpeg"/>
            Intent().also {
                it.action = "android.intent.action.west"
	            it.setDataAndType(Uri.parse("west://com.example.west"), "image/*")
                startActivity(it)
            }

该intent能够启动对应的activity,mimeType=“image/*”,表示启动所有图片类型的activity,intent-filter指定data的mimeType为“image/jpeg”表示我的activity可以处理jpeg类型的图片,所以可以启动,URI中的scheme和host也是匹配的。
《Android开发艺术探索》中提到:“scheme”是有默认值的,为"file"或“content”,也就是说,我们在AndroidManifest中写data时,可以不写scheme,它的默认值就是file或content,通过intent匹配时,scheme要指定为file或者content就可以匹配(file亲测不行,content可以)。

  • 如果没有指定scheme,其他参数都是无效的,举例
        <activity
            android:name=".MainActivity2"
            android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.west"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data
                	<!--不指定scheme,默认用content可以启动-->
                    android:host="com.example.west"
                    android:mimeType="image/jpeg"/>
            </intent-filter>
        </activity>
	it.action = "android.intent.action.west"
	it.setDataAndType(Uri.parse("content://com.exfample.west"), "image/*")
	val resolveActivity = packageManager
		.resolveActivity(it, PackageManager.MATCH_DEFAULT_ONLY)
	startActivity(it)

这里的host和androidManifest中对不上,但是隐式启动activity成功,说明我们没在androidManifest中指定scheme,其他参数都是无效的,这里URI的scheme需要写成content,原因上面有提到。

使用隐式启动时,如何避免报错

使用PackageManage的resolveActivity

it.action = "android.intent.action.west"
it.setDataAndType(Uri.parse("content://com.exampleeee.west"), "image/*")
val resolveActivity = packageManager.resolveActivity(it, PackageManager.MATCH_DEFAULT_ONLY)

如果我们的intent-filter规则能够匹配某个activity,resolveActivity返回对应的Activity,否则为null,我们在使用隐式启动前通过resolveActivity判断有没有可以启动的目标Activity即可。

参考资料:《Android开发艺术探索》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值