当前位置:首页 > 芯闻号 > 充电吧
[导读]概述我们知道,Intent是分两种的:显式Intent和隐式Intent。如果一个Intent明确指定了要启动的组件的完整类名,那么这个Intent就是显式Intent,否则就是隐式Intent。当我

概述

我们知道,Intent是分两种的:显式Intent和隐式Intent。如果一个Intent明确指定了要启动的组件的完整类名,那么这个Intent就是显式Intent,否则就是隐式Intent。当我们用一个显式Intent去启动组件时,Android会根据Intent对象所提供的component name直接找到要启动的组件,当我们用一个隐式的Intent去启动组件时,Android系统就无法直接知道要启动的组件名称了,本文就是讲解Android系统如何根据隐式Intent查找匹配到要启动的组件。

当Android系统接收到一个隐式Intent要启动一个Activity(或其他组件)时,Android会根据以下三个信息比较Intent的信息与注册的组件的intent-filter的信息,从而为该Intent选择出最匹配的Activity(或其他组件):

intent中的action

intent中的category

intent中的data(包含Uri以及data的MIME类型)

也就是隐式intent对象要满足要启动的目标组件中注册的intent-filter中的、、三个标签中的信息,即要分别通过action测试、category测试以及data测试。intent-filter信息是在Android的manife文件中描述的,顾名思义,intent-filter是intent过滤器,就是用来过滤intent的。

如果隐式intent对象同时通过了某个组件的中intent-filter的action测试、category测试以及data测试,那么该组件就可以被intent对象所启动。如果隐式intent对象没有通过系统中任何组件的intent-filter测试,那么就没有Android系统无法找到该intent对象要启动的组件。下面我们依次看一下如何才能通过这三个测试。

Action测试

为了指定能够接收并处理的Intent的类型,组件可以在intent-filter中声明其支持0个或多个action,例如:

intent对象可以通过setAction()方法设置唯一的一个action值。对于action测试,需要分两种情况:

intent对象设置了action

如果intent对象通过调用setAction()方法设置了action的值,那么只有当组件的intent-filter中包含了intent对象中的action值的时候,action测试才通过,否则无法通过。

举个例子,假设我们的Activity的intent-filter如下所示:

下面的intent对象可以通过上面intent-filter里面的action测试:

Intent intent = new Intent();

intent.setAction("com.ispring.action.ACTION_TEST1");

Uri uri = Uri.parse("ispring://blog.csdn.net/sunqunsunqun");

intent.setData(uri);

该intent之所以能通过action测试是因为intent-filter中包含该intent的action值com.ispring.action.ACTION_TEST1。

下面的intent对象无法通过上面intent-filter里面的action测试:

Intent intent = new Intent();

intent.setAction("com.ispring.action.ACTION_TEST3");

Uri uri = Uri.parse("ispring://blog.csdn.net/sunqunsunqun");

intent.setData(uri);

该intent之所以无法通过action测试是因为intent-filter中不包含该intent的action值com.ispring.action.ACTION_TEST3。

intent对象没有设置action

如果intent对象没有调用setAction()方法设置action的值,那么如果intent-filter至少有一个任意的action的值,该intent对象就可以通过该intent-filter的action测试,反之,如果intent-filter中没有定义任何的action,那么该intent无法通过该intent-filter的action测试。

举个例子,假设我们的intent对象如下所示:

Intent intent = new Intent();

//不设置action值

//intent.setAction("com.ispring.action.ACTION_TEST1");

Uri uri = Uri.parse("ispring://blog.csdn.net/sunqunsunqun");

intent.setData(uri);

上面的intent对象可以通过如下的intent-filter:

上面的intent对象无法通过如下的intent-filter:

通过上面的几个示例,想必大家都已经理解了action测试的规则,至于上面的category和data标签的使用,会在下面详细介绍。

总结起来有两点结论:

1. 要想让intent对象通过action测试,那么intent-filter中声明的action不能为空且要包含intent对象中的action值(如果intent的action值不为空的话)。

2. 如果intent-filter没有声明任何action,那么所有的intent的对象(即无论intent如何配置)都无法通过intent-filter的action测试。

Category测试

为了指定能够接收并处理的Intent的类型,组件可以在intent-filter中声明其支持0个或多个category,例如:

...

intent对象有addCategory()方法,也就是说一个intent对象也可以关联多个category。为了能让intent对象通过intent-filter的category测试,intent对象中的所有category都要在intent-filter中找到对应项。

具体来说,又分为如下两种情况:

intent对象至少有一个category

这种情况下,假设intent对象有N个category(N >=1),那么intent-filter中必须要包含这N个category,intent对象才能通过category测试,否则无法通过测试。如果用intent对象启动Activity,还有其他限制条件,会在后面详细说明。

举个例子,假设我们的intent-filter如下所示:

以下intent对象能够通过category测试

Intent intent = new Intent();

intent.setAction("com.ispring.action.ACTION_TEST1");

intent.addCategory("com.ispring.category.TEST1");

intent.addCategory("com.ispring.category.TEST2");

该intent对象之所以可以通过category测试是因为intent-filter包含了该intent对中所有的category值:com.ispring.category.TEST1”和com.ispring.category.TEST2。

以下intent对象无法通过category测试

Intent intent = new Intent();

intent.setAction("com.ispring.action.ACTION_TEST1");

intent.addCategory("com.ispring.category.TEST1");

intent.addCategory("com.ispring.category.TEST3");

该intent之所以无法通过上面的intent-filter的category测试是因为intent-filter只包含了该intent中值为com.ispring.category.TEST1的category,而并未包含值为com.ispring.category.TEST3的category,不满足完全包含intent中全部category的情况。

intent对象不包含任何category

如果intent对象没有调用过addCategory()方法,那么intent对象就不包含任何的category。这种情形下,如果该intent不是用来启动Activity的话,那么无论intent-filter中category中如何配置,intent对象总是能通过intent-filter的category测试,即便intent-filter中没有声明任何的category,intent都能通过category测试。此处强调了该intent不是用来启动Activity这种条件,会在下面详细解释。

此处需要特别说明的是,我们在上面所有的示例中,都给Activity的intent-filter添加了值为android.intent.category.DEFAULT的category,这是因为当我们把一个隐式的intent传递给startActivity()或startActivityForResult()方法时,Android会自动给该隐式intent添加值为android.intent.category.DEFAULT的category,所以为了能让intent-filter包含intent中全部的category,我们就需要在Activity的intent-filter中添加该category,在使用时需要特别注意。

根据上面我们的几个示例,我们总结如下:

1. 如果intent对象不包含任何category,并且该intent不是用来启动Activity的,那么该intent对象总是能通过所有任意的intent-filter的category测试;

2. 如果intent对象包含category(至少一个),那么只有当intent-filter中声明的category全部包含intent对象中的所有category的时候才通过category测试。

3. 如果允许Activity被隐式的Intent启动,那么我们必须在该Activity的intent-filter中声明值为android.intent.category.DEFAULT的category。

Data测试

为了指定可以接收的Intent的data,intent-filter需要声明0个多多个标签,例如:

...

每个标签都可以指定一个URI结构以及data的MIME类型。一个完整的URI由scheme、host、port和path组成,其结构如下所示:

://:/

其中scheme既可以是Android中常见的协议,也可以是我们自定义的协议。Android中常见的协议包括content协议、http协议、file协议等,自定义协议可以使用自定义的字符串。

如下是一个content协议的URI:

content://com.example.project:200/folder/subfolder/etc

在该URI中,scheme是content,host是com.example.project,port是200,path是folder/subfolder/etc。

如下是一个自定义协议的URI:

ispring://blog.csdn.NET/sunqunsunqun

在该URI中,scheme是ispring,host是blog.csdn.Net,没有明确设定port,path是sunqunsunqun。

组成URI的这些属性在标签中都是可选的 ,但存在如下的依赖关系:

如果没有指定scheme,那么host参数会被忽略

如果没有指定host,那么port参数会被忽略

如果scheme和host都没有指定,path参数会被忽略

当我们将intent对象中的Uri参数与intent-filter中的标签指定的URI格式进行对别时,我们我们只对比intent-filter的标签指定的部分,例如:

如果intent-filter中只指定了scheme,那么所有带有该sheme的URI都能匹配到该intent-filter。

如果intent-filter中只指定了scheme和authority(authority包括host和port两部分)而没有指定path,那么所有具有相同scheme和authority的URI都能匹配到该intent-filter,而不用考虑path为何值。

如果intent-filter中同时指定了scheme、authority和path,那么只有具有相同scheme、authority和path的URI才能匹配到该intent-filter。

需要注意的是,intent-filter的标签在指定path的值时,可以在里面使用通配符*,起到部分匹配的效果。

data测试需要同时将intent对象中的URI、MIME类型与intent-filter的标签中指定的URI、MIME类型进行对比。

我们知道一个intent-filter下可以有多个标签,intent对象无需通过所有的标签测试,一般情况下,我们的intent对象只需通过了其中一个标签的测试并满足某些特定情形下的一些条件,那么该intent对象就通过了该intent-filter的data测试。

进行对比的规则分以下几种情况:

intent对象不包含URI和MIME类型

这种情况下,只有当intent-filter也没有指定任何URI和MIME类型的时候才能通过data测试。

例如我们有如下intent对象:

Intent intent = new Intent();

intent.setAction("com.ispring.action.ACTION_TEST1");

上面的intent对象可以通过下面的intent-filter的data测试:

上面的intent对象无法通过下面的intent-filter测试:

intent对象包含URI但不包含MIME类型

这种情况下,只有当intent对象的URI匹配到了intent-filter中的URI格式,并且intent-filter没有指定MIME类型的时候才能通过data测试。需要注意的是,这里所说的intent-filter没有指定MIME类型的情形指的是intent-filter中所有的标签都没有指定MIME类型,即整个intent-filter中完全没有android:mimeType这几个字,理解这点很重要,大家在下面的几个示例中可以体会到这点。

例如有如下intent对象:

Intent intent = new Intent();

intent.setAction("com.ispring.action.ACTION_TEST1");

Uri uri = Uri.parse("ispring://blog.csdn.net/sunqunsunqun");

intent.setData(uri);

上面的intent能通过如下的intent-filter的data测试:

上面的intent对象可以通过以下intent-filter的data测试:

intent对象虽然不能通过scheme为sunqun的标签测试,但是可以通过scheme为ispring的data标签测试,且intent对象和intent-filter中的两个标签都没有指定MIME,所以上面的intent对象可以通过该intent-filter测试。

上面的intent对象无法通过以下intent-filter的标签测试:

上面的intent对象之所以不能通过intent-filter中唯一的一个标签测试是因为我们的intent对象没有指定MIME类型,但是上面的标签通过android:mimeType="text/plain"设置了MIME类型。

上面的intent对象无法通过以下intent-filter的data测试:

上面的intent对象之所以无法通过该intent-filter中的data测试,是因为intent对象没有设置MIME类型,但是intent-filter中第二个data标签通过android:mimeType="text/plain"设置了MIME类型。

intent对象包含MIME类型但不包含URI

这种情况下,只有当intent中的MIME类型与intent-filter中列出的MIME类型相同,并且intent-filter没有指定任何的URI格式的时候才能通过data测试。需要注意的是,这里所说的intent-filter没有指定任何的URI格式的情形指的是intent-filter中所有标签都没有指定URI,即整个intent-filter中完全没有android:scheme、android:host、android:port以及android:path,理解这点很重要,大家在下面的几个示例中可以体会到这点。

例如有如下intent对象:

Intent intent = new Intent();

intent.setAction("com.ispring.action.ACTION_TEST1");

intent.setType("text/plain");

上面的intent对象可以通过以下intent-filter的data测试:

上面的intent对象可以通过下面的intent-filter的data测试:

上面的intent对象虽然没有通过MIME类型为image/*的第一个data标签测试,但能通过第二个data标签测试,并且intent对象和intent-filter都没有指定任何的URI格式。

上面的intent对象不能通过以下intent-filter中的data测试:

上面的intent对象中没有设置URI信息,但是在该intent-filter中设置了URI中的scheme值,所以intent无法通过intent-filter的data测试。

上面的intent对象无法通过以下intent-filter中的data测试:

上面的intent对象没有指定URI信息,但是上面的intent-filter中第二个标签设置了URI中的scheme信息,所以intent对象无法通过该intent-filter的data测试。

intent对象同时包含URI和MIME类型

这种情况下,要分别测试URI以及MIME类型测试是否通过,只有URI以及MIME测试都通过了,data测试才能通过。

对于MIME测试:如果intent的MIME类型能够匹配intent-filter中列出的某一个标签中的MIME类型值,那么MIME类型测试就通过了。

对于URI测试:

又细分两种情况,满足下面的任何一种情况都可以通过URI测试。

如果intent的URI格式能够匹配intent-filter中列出的某一个中的URI,那么URI测试就通过了。

如果intent的URI是content:协议或file:协议,并且整个intent-filter的所有标签中都没有指定URI,那么该intent也能通过URI测试。换句话说,如果一个intent-filter只列出了MIME类型,没有列出任何URI相关的格式的话,那么这个intent-filter就默认是支持content:协议或file:协议的。

下面举几个例子大家自己体会一下。

假设有如下协议为自定义协议ispring:的intent对象:

Intent intent = new Intent();

intent.setAction("com.ispring.action.ACTION_TEST1");

Uri uri = Uri.parse("ispring://blog.csdn.net/sunqunsunqun");

String type = "text/plain";

intent.setDataAndType(uri, type);

上面的intent对象可以通过下面的intent-filter的data测试:

上面的intent对象无法通过下面的intent-filter的data测试:

port不满足,URI测试不通过,导致data测试失败。

上面的intent对象无法通过下面的intent-filter的data测试:

android:mimeType不满足,MIME类型测试不通过,导致data测试失败。

假设有如下协议为content:的intent对象:

Intent intent = new Intent();

intent.setAction("com.ispring.action.ACTION_TEST1");

Uri uri = Uri.parse("content://com.ispring.test");

String type = "text/plain";

intent.setDataAndType(uri, type);

上面的intent对象无法通过下面的intent-filter的data测试:

URI中的scheme不匹配,导致URI测试不通过,导致data测试失败。

上面的intent对象可以通过下面的intent-filter的data测试:

intent中使用的是content:协议,并且整个intent-filter中都没有定义URI格式,所以URI测试是可以通过的,并且MIME类型能找到匹配项,所以可以通过data测试。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

罗德与施瓦茨与SmartViser携手开发了一种用于测试符合欧盟销售的智能手机和平板电脑的新Energy Efficiency Index(EEI)标签法规的解决方案。该解决方案的核心是R&S CMX500,这是...

关键字: 智能手机 Android iOS

(全球TMT2023年8月24日讯)2023年8月23日,时值实时3D引擎Unity在华设立合资公司Unity中国一周年之际,Unity中国正式推出Unity中国版引擎——团结引擎。Unity全球CEO John Ri...

关键字: UNITY CE Android 开发者

报告显示:全球电商 App 获客花费接近50亿美元 北京2023年8月23日 /美通社/ -- 全球营销衡量与体验管理平台 AppsFlyer 近日发布《2023 电商 App 营销现状报告》。尽管面临全球经...

关键字: APPS BSP iOS Android

数字机顶盒是一种数字技术下的多媒体娱乐中心,可以实现电视节目接收、播放、存储、网络应用等多种功能。随着科技的发展,数字机顶盒的设计方案也在不断进步和优化。本文将介绍数字机顶盒设计的几种实现方案。

关键字: 数字机顶盒 Android Linux

21ic 近日获悉,原小米 9 号创始员工李明在社交媒体平台公布了旗下首款产品乐天派桌面机器人,为全球首款 Android 桌面机器人,面向极客和发烧友的 AI + 机器人。据悉,李明两个月前宣布创业并进军 AI 领域,...

关键字: 小米 Android 桌面机器人 AI

尽管安装增长放缓,全球游戏 App 获客花费仍高达 267 亿美元 经济低迷导致 2023 游戏 App 营销优先考虑收入指标,用户增长次之 北京2023年3月9日 /美通社/ -- 今天,全球营销衡量与体验管理平台...

关键字: APPS iOS Android BSP

量子计算领域的新里程碑,来了! 谷歌科学家证明,通过增加量子比特的数量,就能降低量子计算的错误率。

关键字: 谷歌 Android Windows

「卫星通讯」正在被普及到每一台智能手机当中。普及的动机并非是消费市场的一个刚需,其实更像是将差异化的功能「抹平」成一个标配。时下,支持「卫星通讯」功能的智能手机只有苹果的 iPhone 14 系列与华为的 Mate 50...

关键字: 卫星通讯 Android 智能手机 iPhone

Android是Google开发的操作系统,支持多种指令集架构 (ISA),包括Arm和x86,多数使用Android的设备都采用Arm架构芯片组。新兴RISC-V架构是免费开放指令集架构,任何人都可用它设计芯片,且无需...

关键字: 谷歌 Android RISC-V架构

智能手机并非每年都取得重大进展,这导致越来越多的人将手机保留两年、三年或四年。不过,普通的 Android 手机能否在遇到问题之前使用那么久?

关键字: Android 安卓 谷歌 智能手机
关闭
关闭