【Android Activity】IntentFilter的匹配规则

启动 Activity 分为两种,显式调用和隐式调用。显式调用需要明确指出被启动组件的包名类名。隐式调用需要 Intent 能够匹配目标组件的 IntentFilter 中所设置的过滤信息,如果不匹配将无法启动目标 Activity

一、IntentFilter 简介

  • 意图过滤器的意思
  • manifest文件中activity标签的子标签。
  • IntentFilter 的过滤信息(子标签)有 action、category、data
1、IntentFilter 注意点

1、一个activity下可能有多个intentfilter,一个intent只要能匹配任何一组intentFilter下的信息便可成功启动activity。
2、一个intentFilter中action 、category、data都可以有多个。
3、想要隐式开启activity 必须在intentFilter添加 <category android:name=“android.intent.category.DEFAULT” />

二、Action规则

1、系统定义了一些Action字符串
 <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
  </activity>
2、我们也可以自定义Action字符串
 <activity android:name=".ActivityC">
            <intent-filter>
                <action android:name="com.example.test" />//添加自定义字符串即可
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
 </activity>
3、Action匹配规则

1、intentFilter中的action可以有很多,只要intent添加的action和intentFilter中其中一个action匹配即可
2、action区分大小写,大小写不同的字符串是不同的action。
3、intentFilter 至少要有一个action

4、栗子
Intent intent = new Intent();
intent.setAction("com.example.test"); //intent 添加action。匹配intent-filter 下的一个action即可成功打开activity
startActivity(intent);

<activity android:name=".ActivityC">
            <intent-filter>
                <action android:name="com.example.test" />
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
 </activity>

三、Category规则

1、匹配规则
1、intentFilter中的category可以有很多,只要intent设置的category和intentFilter的匹配即可。

2、系统在调用startActivity或者startActivityForResult时,会默认为intent加上了android.intent.category.DEFAULT这个category。所以为了activity能够接受隐式调用必须在intentFilter下设置android.intent.category.DEFAULT。

2、栗子

mainactivity开启main2Activity。

#MainActivity
在这里插入图片描述

#main2activity的配置
在这里插入图片描述

#点击按钮(直接崩溃 如下)
在这里插入图片描述

找不到activity?我明明添加了action还和intentFilter下的其中一个action匹配,并且我添加了category也匹配了。这是为啥???还记得我们之前说过得系统在调用startActivity或者startActivityForResult时,默认为intent加上了android.intent.category.DEFAULT这个categor所以要想隐式开启activity这个categrory必须添加待intent-filter中。

 Intent intent = new Intent();
 intent.setAction("com.example.test1");
 intent.addCategory(Intent.CATEGORY_DEFAULT); // 实际还有这个 系统封装在startActivity中了
 intent.addCategory("com.example.category2");
 startActivity(intent);

在这里插入图片描述

四、 data匹配规则

1、data简介

data由两部分组成mimeType和URI,语法如下。

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

1、媒体类型,如image/jpeg 、audio/mpeng4-generic、vodeo/* 可以表示图片文本视屏等不同媒体格式。
2、data 中可以不指定这个属性。
3、假如data指定了mimeType,未制定scheme,scheme默认为content或file
4、scheme必须为小写字母

3、URI结构
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

(1)scheme:URI的模式,常见为http,https,file,content这些字符串,当然也可以为其他任意字符串

(2) Host:URI的主机名比如 “www.baidu.com”

(3)Port:URI中的端口号,比如80

(4)parth ,pathPattern,pathPrefix 这三个参数表示路径信息。

4、栗子

(1)简单使用

            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data
                    android:host="com.test"
                    android:scheme="test" />
            </intent-filter>

如上就是最简单的url匹配了,此时只要是 uri的scheme为test,host为test://com.text 就能正确匹配。

        startActivity(Intent().apply {
            action = Intent.ACTION_VIEW
            addCategory(Intent.CATEGORY_DEFAULT)
            data = Uri.parse("test://com.test")
          //  如下都满足  
          //  data = Uri.parse("test://com.test/b")
          //  data = Uri.parse("test://com.test/b/a.txt")
          //  data = Uri.parse("test://com.test/b/?articleId=1")
        })

(2)path属性

这个代表指定精确的path ,错一点就匹配失败如

            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data
                <!-- path 这里必须以/开头 -->
                    android:path="/a" 
                    android:host="com.test"
                    android:scheme="test" />
            </intent-filter>
        startActivity(Intent().apply {
            action = Intent.ACTION_VIEW
            addCategory(Intent.CATEGORY_DEFAULT)
            data = Uri.parse("test://com.test/a")
           // data = Uri.parse("test://com.test/a/b") // 匹配失败
        })

(3)pathPattern

上面介绍了path的用法可是弊端太多如我想支持 b路径下的所有怎么办呢?我们可以如下配置

            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data
                    android:pathPattern="/b/.*"
                    android:host="com.test"
                    android:scheme="test" />
            </intent-filter>

pathPattern这个类似正则的概念,但是系统支持的正则符号太少:

. 表示任意字符
* 表示0个或者多个
[] 表示范围。如[0-9]、[a-z] 。[] 可结合^使用标识否定
+ 表示零次或多次
{number} 表示number次

5、tips

1、URI是有默认值的。URI默认值为content或file。
2、如果需要为intent指定完整的data需要调用intent.setDataAndType(uri,type);这个方法,
3、setData 设置data的uri,setType 设置data的miniType但是 setData setType这两个方法彼此会清除对方值。(参考两个方法源码)

这样匹配规则就总结完了,另外注意intentFilter的匹配规则对Service,broadcastReceiver同样适用,不过系统对于Service的建议尽量使用显示意图来启动服务。
当组件设置了intent filter后便可支持隐式开启,这时exported属性默认会为true,组件支持外部应用开启。无intent filtre时组件的exported默认为false。

五、activity相关的常用方法

1、onNewIntent 触发条件有哪些?

1、activity 设置为SingleTop 且位于栈顶:再次开启activity会走 onNewIntent
2、activity设置为SingleTask、singleinstance任务栈中存在实例:再次开启activity会走onNewIntent

2、resolveActivity

避免找不到隐式activity而crash。注意参数PackageManager.MATH_DEFAULT_ONLY的使用。

if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
            startActivity(intent);
        } else {
            Toast.makeText(this, "Activity Not Found", Toast.LENGTH_SHORT).show();
        }
4、异常状态下的数据恢复

onSaveInstanceState()
onRestoreInstanceState()

#思想:委托思想

首先 Activity 被意外终止时,Activity 会调用 onSaveInstanceState 去保存数据,然后 Activity 会委托 Window 去保存数据,接着 Window 在委托它上面的顶级容器再去一一通知它的子元素来保存数据,这样整个数据保存过程就完成了。

5、startActivityForResult使用

#mainActivity

   ...
   ...
   Intent intent = new Intent(this, SecondActivity.class);
   startActivityForResult(intent, 0x01);
   ...
   ...

 @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 0x01 && resultCode == 0x02
                && data != null) {
            // todo
        }
    }

#secondActivity

        Intent intent = new Intent();
        intent.putExtra("name", "i am second");
        setResult(0x02, intent);
        finish();

The end

data规则官方文档

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值