Android中Activity显式调用和隐式调用的区别以及Intent Filter知识点总结

前言

测试代码时写的项目,基本就是正文的代码
https://github.com/wodongx123/startActivityDemo

1. 显式调用和隐式调用

Activity的启动分为两种,显示调用和隐式调用。不过在绝大部分的情况下,我们一般都是使用显示调用,只有少部分情况时会用上隐式调用。

1.1 显示调用

需要明确指定被启动对象的组件信息的调用方式,是显式调用,显式调用Activity有三种不同方式

  1. 常见的指明目标Activity的class类。
    /**
     * 显式启动Activity
     */
    private void explicitStart() {
        Intent intent = new Intent(this, SecondActivity.class);
        startActivity(intent);
    }
    
  2. 通过Intent的ComponentName启动Activity。
        // 第一个参数是包名,第二个参数是包下的类名。包名可以直接用getPackageName()方法代替,也可以直接输入当前包的环境
        ComponentName c = new ComponentName("com.wodongx123.startactivitydemo", "com.wodongx123.startactivitydemo.SecondActivity");
        //ComponentName c = new ComponentName(getPackageName(), getPackageName() + ".SecondActivity");
        //ComponentName c = new ComponentName(getApplicationContext(), getPackageName() + ".SecondActivity");
        Intent intent1 = new Intent();
        intent1.setComponent(c);
        startActivity(intent1);
    
  3. 直接指定类名启动。
            
    Intent intent2 = new Intent();
    // 第一个参数是包名,第二个参数是包下的类名。包名可以直接用getPackageName()方法代替,也可以直接输入当前包的环境
    //intent2.setClassName("com.wodongx123.startactivitydemo", "com.wodongx123.startactivitydemo.SecondActivity");
    intent2.setClassName(getApplicationContext(), "com.wodongx123.startactivitydemo.SecondActivity");
    startActivity(intent2);
    

注:网上搜来的资料是说,第一个参数填当前类名,第二个参数填目标类名。我自己实际测试了之后发现这么填是会报错的。可能是因为我的操作方式不对也可能是因为版本更新后不支持以前的方式了。

1.2 隐式调用

概念和显示调用相对,不指明目标Activity的具体信息,Intent会根据Intent Filter所设置的过滤信息去挨个比对,如果匹配成功后就会启动对应的Activity。

Intent Filter设置的过滤信息主要有三个:action,data,category。关于过滤信息的内容下面会详细介绍,先看启动的示例。

  1. 先在AndroidManifest.xml中,将目标Activity设置action和category,两者的值都是字符串,所以随意设置即可。
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.wodongx123.startactivitydemo">
    
        <application
       
    	    ......省略无关代码
    	    
            >
    
    		......省略无关代码
    
            <activity android:name=".ThirdActivity">
                <intent-filter>
                    <action android:name="a"/>
                    <category android:name="b"/>
                    
                    <!-- 无论设置了哪些内容,最后都要加上这个,否则无法启动-->
                    <category android:name="android.intent.category.DEFAULT"/> 
                </intent-filter>
            </activity>
            
        </application>
    </manifest>
    
  2. 然后在Activity中启动
    private void implicitStart() {
        Intent intent = new Intent();
        intent.setAction("a");
        intent.addCategory("b");
        startActivity(intent);
    }
    

2. Intent Filter

  1. 一个Activity可以有多个Intent Filter,我们的Intent只要能匹配其中一个Intent Filter就能成功启动。
  2. 一个Intent Filter中可以有多个Action,category,data,只有Intent中的Action,category,data三个字段都完全按照匹配规则匹配之后,才算成功匹配这个Intent Filter。

2.1 Action的匹配规则

action是一个字符串,也就是说无论是你在Intent Filter写的内容,还是Intent中setAction中,都是填写的字符串。

  1. Intent中的Action必须完全和Intent Filter中的Action一样。
  2. Intent Filter中必须有至少一个Action。
  3. 如果Intent Filter中有多个Action,那么Intent只需要匹配其中一个即可。
  4. Action的内容区分大小写。

示例:

<activity android:name=".test2.ActionTestActivity">
    <intent-filter>
    	<!-- 设置多个action,匹配一个即可打开-->
        <action android:name="test1"/>
        <action android:name="test2"/>
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
/**
 * 测试Action的匹配规则
 */
private void actionTest() {
    Intent intent = new Intent();
    intent.setAction("test1");
    startActivity(intent);
}

2.2 Category的匹配规则

Category也是一个字符串,但是区别于Action的是,Intent中可以同时添加多个Category。

  1. Intent Filter中必须要添加android.intent.category.DEFAULT这一条category(除了App启动的Intent Filter外)。
  2. Intent中如果含有category,那么所有的category都必须符合Intent Filter中的category。
  3. Intent中如果没有category,那么只要Action匹配成功即可。
  4. 综合一下2和3,即Intent中的category要是Intent Filter中category的子集。
<activity android:name=".test2.CategoryTestActivity">
    <intent-filter>
        <action android:name="t" />

        <category android:name="cate1" />
        <category android:name="cate2" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
/**
 * 测试category的匹配规则
 * 取消category2的注释后运行,然后取消category3的注释后再次运行,查看结果
 */
private void categoryTest() {
    Intent intent = new Intent();

    intent.setAction("t");
    intent.addCategory("cate1");
    //intent.addCategory("cate2");
    //intent.addCategory("cate3"); //运行失败
    try {
        startActivity(intent);
    }catch (Exception e){
        e.printStackTrace();
    }
}

2.3 Data的匹配规则

由于Data不像Category和Action一样是一个单字符串(只有一个android:name),所以先看一下Data的结构。

<!-- String表示是字符串类型 -->
<data android:scheme="string"
	android:host="string"
	android:port="string"
	android:path="string"
	android:pathPattern="string"
	android:pathPrefix="string"
	android:mimeType="string" />

内容虽然看着多,但是其实就分为两个部分,从scheme到pathPrefix,都是Uri的一部分,mimeType单独是一部分。

mimeType是媒体类型,比如image/png,audio/mpeg4-generic之类不同的媒体格式。支持用*通配符,关于媒体类型列表,一般所用的类型点这里,当然由于是字符串,也可以根据具体需求自创一个类型。

Uri是用于定位各种各样的资源的字符串,包括本地的和互联网的。直接看一下URI的结构和示例就能理解:

结构:
<scheme>://<host>:<port>/[<path>/<[pathPrefix>/<pathPattern>]
示例:
https://www.baidu.com:80/search/info

最后介绍一下匹配规则,规则很简单,Intent Filter中出现哪个字段,Uri和mimeType的对应部分就要完全一样,不出现可以无视(比如说你可以只设置mimeType而不设置Uri的任何内容)。Intent Filter可以有多个data,Intent只要能匹配其中一个即可。

示例1(只设置mimeType也能匹配):

<activity android:name=".test2.DataTestActivity">
    <intent-filter>
        <action android:name="t1"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="image/png" />
    </intent-filter>
</activity>
/**
 * 测试Data的匹配规则(只设置mimeType)
 */
private void dataTest() {
    Intent intent = new Intent();
    intent.setAction("t1");
    intent.setType("image/png");
    //intent.setType("image/jpeg"); //运行失败
    try {
        startActivity(intent);
    }catch (Exception e){
        e.printStackTrace();
    }
}

示例2:(设置mimeType和Uri)

<activity android:name=".test2.DataTestActivity">
    <intent-filter>
        <action android:name="t2"/>
        <data android:mimeType="image/jpeg"
            android:scheme="https"
            android:host="www.baidu.com"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>
/**
 * 测试Data的匹配规则(设置mimeType和URI)
 * 切换不同的URI查看结果
 */
private void dataTest1() {
    Intent intent = new Intent();
    intent.setAction("t2");
    intent.setDataAndType(Uri.parse("https://www.baidu.com/aaa"), "image/jpeg");
    //intent.setDataAndType(Uri.parse("https://www.tecent.com/aaa"), "image/jpeg");
    try {
        startActivity(intent);
    }catch (Exception e){
        e.printStackTrace();
    }
}

2.3.1 URI的属性

scheme:Uri的模式,http、https、file、content等,Uri如果没有scheme其他参数无效,整个Uri也无效。
host:Uri的主机名,比如www.baidu.com,Uri如果没有host,整个Uri还是无效。
Port:Uri中的端口号,仅当Uri中指定了scheme和host时才有效。
path、pathPattern、PathPrefix:三个参数都表示路径信息,其中path表示完整的路径信息;pathPattern也表示完整的路径信息,但是它可以包含通配符‘*’,可以匹配0个或多个字符,需要注意的是由于正则表达式的规范,如果想表达真实的字符串,‘*’要写成‘\\*’,‘\’要写成‘\\\\’;PathPrefix表示路径的前缀信息。

2.4 Intent

我们都知道,Intent的作用不仅仅是用于Activity的启动,它是关联四大组件的重要内容,而四大组件都要在AndroidManifest.xml中注册,所以刚刚关于Intent Filter的一切内容,不仅限于Activity,在Service和BroadcastReceiver中也能同样的使用。

3. 隐式调用的其他内容

3.1 关于android.intent.category.DEFAULT

在Intent Filter的设置中,android.intent.category.DEFAULT这个变量是必须要加上的,如果不加的话,哪怕其他字段都匹配成功隐式启动时也会直接找不到对应的Activity然后报错。

那么具体是什么原因会导致这样呢?

实际上,我们在启动Activity,调用startActivity或者startActivityForResult方法时,会自动的为Intent添加一个android.intent.category.DEFAULT的category。由于category的匹配规则,所以我们每个Intent Filter都要加上android.intent.category.DEFAULT才能正常进行匹配。

3.2 系统自带的一些隐式调用的Activity

其实我们很多时候就已经会用隐式调用的方法调用Android系统内置的一些Activity了,比如打电话。

// 要在AndroidManifest.xml中先加上<uses-permission android:name="android.permission.CALL_PHONE"/>
String tel = "110";
//隐式调用,第一个参数是Action,第二个参数是data
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + tel));
startActivity(intent);

开网页:

Intent intent1 = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.baidu.com"));
startActivity(intent1);

3.3 同时出现多个Activity匹配

如果同时出现多个Activity匹配我们的隐式调用时,会怎么样?答案很简单,系统会让你选择要启动的对应Activity
以刚刚的打开网页为例,如果你的手机里面有装其他浏览器的话,会变成这样:
在这里插入图片描述

3.4 为什么需要隐式调用Activity,隐式调用Activity的应用场景

其实在讲完隐式启动之后,这个问题的答案已经不言而喻了,隐式启动的应用场景主要是用于应用程序间的数据互通,也就是SDK开发,当你的某个页面需要让其他应用程序调用的时候,只要对接完Intent Filter中的数据,对方的应用程序就可以直接打开你所指定的页面,不过一般情况下是己方的程序员写完这一套流程封装成aar后,对方直接导入后使用就是了(比如支付宝的支付接口)。

参考材料

Android开发艺术探索
p28 - p34.
Android 启动一个Activity的几种方式 - 相伴流年 - 博客园
https://www.cnblogs.com/cyqx/p/10927458.html
隐式启动Activity_qinxue24的博客-CSDN博客
https://blog.csdn.net/qinxue24/article/details/72818510
为什么默认需加android.intent.category.DEFAULT - Holyday - 博客园
https://www.cnblogs.com/holyday/p/7204487.html
Intent的属性及Intent-filter配置——Data、Type属性与intent-filter配置 - TealerProg - 博客园
https://www.cnblogs.com/wolipengbo/p/3427574.html

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android,我们可以使用隐式意图(Intent)来打开一个新的Activity隐式意图是指没有明确指明目标组件的意图,而是通过指定一些匹配条件来启动匹配的组件。 下面是一个使用隐式方式打开一个新的Activity的示例代码: ```java Intent intent = new Intent(); intent.setAction("com.example.action.OPEN_NEW_ACTIVITY"); intent.addCategory("android.intent.category.DEFAULT"); startActivity(intent); ``` 上面的代码,我们首先创建了一个Intent对象,然后通过调用setAction()方法来设置Action,这里设置的是"com.example.action.OPEN_NEW_ACTIVITY"。接着,我们调用addCategory()方法来添加Category,这里添加的是"android.intent.category.DEFAULT"。最后,我们调用startActivity()方法来启动Activity。 在这个示例,我们没有明确指定要启动哪个Activity,而是通过设置Action和Category来启动匹配的Activity。具体来说,我们要求被启动Activity必须满足以下条件: - Action为"com.example.action.OPEN_NEW_ACTIVITY"。 - Category包含"android.intent.category.DEFAULT"。 如果有多个Activity同时满足这些条件,系统会弹出一个选择对话框让用户选择要启动Activity。 需要注意的是,如果要使用隐式方式启动Activity,需要在被启动ActivityAndroidManifest.xml文件设置正确的Intent过滤器。具体来说,需要在<activity>标签添加一个<intent-filter>标签,并在其设置Action和Category。例如: ```xml <activity android:name=".NewActivity"> <intent-filter> <action android:name="com.example.action.OPEN_NEW_ACTIVITY" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> ``` 上面的代码,我们在<activity>标签添加了一个<intent-filter>标签,并在其设置了Action和Category,这样就可以响应隐式意图了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值