隐式意图:在程序中没有为Intent
对象的mComponent
属性明确指出想要其启动组件。
隐式意图仅仅是为Intent
对象指出一些筛选条件,然后Android
系统会取出Intent
对象中的数据和所有已经注册到系统中的组件进行匹配。
- 若匹配成功,则系统将激活该组件。 - 若有多个组件匹配成功,则系统将弹出一个对话框,要求用户选择所要激活的组件。 - 若没有任何组件匹配成功则抛异常。
应用程序中定义的Android
组件都需要在AndroidManifest.xml
文件中记录。当系统在进行意图匹配时,就会取出Intent
对象中的筛选条件与所有已注册到系统中的各个组件的<intent-filter>
标签下定义的数据进行匹配。
上面所说的“筛选条件”指的就是Intent
对象以下三个方面:
1、动作(mAction)
2、数据(mData和mType)
3、分类(mCategories)
也就是说,我们通过为Intent的上面四个属性赋值,来执行“设置筛选条件”,然后操作系统也会读取这四个属性,并用它们进行匹配。
动作
mAction
:是String
类型的,用来告诉系统本次请求要执行什么样的动作。如:张三看书、李四唱歌中的“看”
、“唱”
就是指动作。在Android中内置的动作有很多,常见的有:
- Intent.ACTION_VIEW :“查看”动作。 - Intent.ACTION_EDIT :“编辑”动作。 - Intent.ACTION_DELETE :“删除”动作。 - Intent.ACTION_CALL:“呼叫”动作,通常指打电话。 - Intent.ACTION_MAIN :标记当前Activity是程序的入口。
数据
数据:“动作”
所要操作的数据,显然不同的动作要跟不同的数据规范类型配合使用,比如:
- 如果动作是ACTION_VIEW,那么数据就应该指向一个可被查看的东西,比如网页、图片、视频等。 - 如果动作字段是ACTION_EDIT,那么它的数据应该指向它所要编辑的数据。 - 如果动作是ACTION_CALL,那么数据就应该是一个呼叫号码。
再具体点说,数据包括两部分:mData
和mType
:
- 数据的URI(mData):用来指出数据所在的位置。如file:///tmp/android.txt。 - 数据的类型(mType):用来指出数据的MIME类型。如:text/html 。
分类
mCategories
:“动作”
的附加信息(可以有多个)。在Android中内置的类型有:
- Intent.CATEGORY_LAUNCHER :目标Activity能够被列在应用程序启动器上。 - Intent.CATEGORY_BROWSABLE :目标Activity能够安全的调用浏览器来显示链接所指向的数据(如图片或电子邮件)。 - Intent.CATEGORY_HOME :目标Activity显示在主屏幕上。
通过前面的介绍,我们已经知道这三点:
- 创建完Activity等组件后,还需要在清单文件中配置它们,以便让系统知道这些组件的存在。 - 在配置它们的时候,除了ContentProvider之外的另外三个组件都可以配置一个或多个<IntentFilter>,它表示过滤器。 - 当我们需要启动一个组件时,整个流程是这样的: - 首先,我们创建一个Intent对象,然后将它传递给操作系统。 - 然后,系统会检测Intent,若它是显式意图的直接启动目标组件,否则会依据Intent内部的信息进行匹配。 - 接着,如果我们调用的startActivity来启动组件,那么系统会获取当前所有注册到系统中的Activity,并获取它们的<IntentFilter>。 - 最后,让Intent对象和这些Activity的<IntentFilter>进行匹配,匹配成功就会启动该Activity,若有多个Activity都匹配成功,则系统会让用户选择启动哪一个。 - 另外,组件可以有多个<IntentFilter>标签,只要该组件有一个匹配成功,则就能启动。
IntentFilter
类与<IntentFilter>
标签对应,它有类似于Intent对象的动作、数据、和分类字段。
Action匹配
在清单文件中的<intent-filter>
元素内的<action>
子元素对应咱们前面说的“动作”。如:
|
|
语句解释:
- 像本例显示的这样,一个过滤器可以列出多个Action。但这个列表不能是空的,一个过滤器必须包含至少一个<action>元素,否则它不会匹配任何Intent对象。 - 要通过这个检测,在Intent对象中指定的Action必须跟这个过滤器的动作列表中的某个Action一致匹配。
进行意图匹配时,只有在Intent的mAction
属性与<intent-filter>
下的某个<action>
标签的值匹配成功后,才会去匹配mCategories
属性。
Category检测
<intent-filter>
元素内的<category>
子元素对应前面说的“分类”。例如:
|
|
对于一个要通过Category
检测的Intent
对象,在Intent
对象中所包含的每个分类,过滤器中都必须得包含,过滤器能够列出Intent中不包含的分类,但是它不能忽略Intent
对象中的任何分类。
因此,原则上一个没有category
的Intent
对象应该始终通过这个检测,而不管过滤器中声明的分类。
注意:
- 所有传递给startActivity()方法的隐式Intent对象,都会至少包含了一个android.intent.category.DEFAULT。 - 只有Intent对象的mCategorie里的所有类型都匹配成功后,才会去匹配<data>标签。
Data检测
像Action
、Category
检测一样,针对IntentFilter
的“数据”也要包含在一个子元素中,这个子元素能够出现0~n
次。例如:
|
|
每个<data>
元素能够指定URI
和数据类型(MIME
)对于每个URI
部分都会有独立的属性:scheme、host、port、path。格式:
|
|
例如,以下URI:
|
|
- scheme是content - host 是com.example.project - port 是200 - path 是folder/subfolder/etc。
其中host
和port
一起构成了authority
,如果没有指定host
,那么port
也会被忽略。
范例1:新建Activity。
|
|
在MainActivity中书写如下跳转语句:
|
|
语句解释:
- 本范例并没有为Intent指定具体要跳转到哪个Activity,而是为Intent指定一个action。 - 在调用startActivity方法启动Activity时,该方法会自动为Intent对象设置一个category,即:“android.intent.category.DEFAULT”。
范例2:data匹配。
|
|
在MainActivity中书写如下跳转语句:
|
|
语句解释:
- 使用scheme属性匹配代码中的协议名。 - 使用host属性匹配代码中的主机名,使用此属性之前,必须要先指定scheme属性,在代码中scheme和host之间要写上“://”作为间隔。 - 使用port属性匹配代码中的端口号,使用path属性匹配代码中的路径。
范例3:数据类型匹配。
|
|
在MainActivity中书写如下跳转语句:
|
|
语句解释:
- 使用mimeType属性可以对数据的MIME类型进行限制。
- 使用setData方法设置Intent的Uri,使用setType方法设置Intent的MIME类型。
- 但是如果你想同时设置这两者,则只能使用setDataAndType方法,因为setData和setType方法中会彼此清除对方的值,具体请查看源码。
在<intent-filter>
中可以不列出<data>
元素,但是只要列出了,那么<data>
中所列出的所有属性都得匹配。
范例4:假设我们有如下配置:
|
|
那么我们可以用如下代码进行匹配:
|
|
语句解释:
- 也就是说,虽然我们没有为<data>元素设置scheme属性,但是它却存在默认值,会默认匹配“file”、“content”。
- 另外,在<data>元素的path和mimeType属性的值中,都可以包含通配符“*”,用来匹配0~n个任意字符。
范例5:安装应用程序。
|
|
语句解释:
- 本范例使用系统内置的ACTION_VIEW动作安装APK文件。 - ACTION_VIEW动作所要操作的数据的Uri是通过一个File对象的路径构造出来的。 - ACTION_VIEW动作用于“查看”,该动作会根据其所要查看的数据的MIME类型的不同,来调用不同的应用程序来查看数据。 - APK文件的MIME类型为application/vnd.android.package-archive ,而查看APK文件,其实就是安装APK文件。
范例6:卸载应用程序。
|
|
语句解释:
- 调用系统内置的ACTION_DELETE动作可以执行删除操作。 - 若删除的数据为:“package:应用程序包名”,则相当于卸载该应用程序。 - 调用Activity的getPackageName()方法可以获取当前应用程序的包名称。
范例7:启动发送短信Acitivity。
|
|
语句解释:
- 程序运行时会打开系统发送短信界面。
扩展:
当我们使用隐式意图启动一个A时,可以做一下判断,看是否有A能够匹配我们的隐式意图,如果不判断就有可能因找不到而报错。
所以我们采用:
PackageManager
类中有一组query…()
以及resolve…()
方法。
前者返回能够接受一个特殊Intent
对象的所有组件,后者返回最佳匹配结果(即只返回1个结果),例如:
- queryIntentActivities(Intent intent,int flags)方法返回能够执行这个Intent对象的所有Activity。
第二个参数我们使用:MATCH_DEFAULT_ONLY 这个表示仅仅匹配那些intent-filter中声明的
<category android:name="android.intent.category.DEFAULT"/>的Activity。因为不含有Default的那些Activity是无法接受隐式意图。 - queryIntentServices()方法类似地返回Service列表。 - queryBroadcastReceivers()方法类似地返回Broadcast Receiver列表。
这些方法都不激活组件,它们只是列出能够响应这个Intent
对象的所有组件。