Intent 是一个消息传递对象,您可以使用它从其他应用组件请求操作。 详见官方文档
主要功能如下:
启动Activity: 通过将 Intent 传递给 startActivity(),您可以启动新的 Activity 实例。Intent 描述了要启动的 Activity,并携带了任何必要的数据。 如果您希望在 Activity 完成后收到结果,请调用 startActivityForResult()。在 Activity 的 onActivityResult() 回调中,您的 Activity 将结果作为单独的 Intent 对象接收。启动服务: 通过将 Intent 传递给 startService(),您可以启动服务执行一次性操作(例如,下载文件)。Intent 描述了要启动的服务,并携带了任何必要的数据。 如果服务旨在使用客户端-服务器接口,则通过将 Intent 传递给 bindService(),您可以从其他组件绑定到此服务。 注意:为了确保应用的安全性,启动 Service 时,请始终使用显式 Intent,且不要为服务声明 Intent 过滤器。使用隐式 Intent 启动服务存在安全隐患,因为您无法确定哪些服务将响应 Intent,且用户无法看到哪些服务已启动。 传递广播: 通过将 Intent 传递给 sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast(),您可以将广播传递给其他应用。两种Intent在启动Activity或Service时的区别:
创建显式Intent启动 Activity 或服务时,系统将立即启动 Intent 对象中指定的应用组件。创建隐式Intent启动Activity,Android 系统通过将 Intent 的内容与在设备上其他应用的清单文件中声明的 Intent 过滤器进行比较,从而找到要启动的相应组件。 如果 Intent 与 Intent 过滤器匹配,则系统将启动该组件,并向其传递 Intent 对象。 如果多个 Intent 过滤器兼容,则系统会显示一个对话框,支持用户选取要使用的应用。 图 1. 隐式 Intent 如何通过系统传递以启动其他 Activity 的图解:[1] Activity A 创建包含操作描述的 Intent,并将其传递给 startActivity()。[2] Android 系统搜索所有应用中与 Intent 匹配的 Intent 过滤器。 找到匹配项之后,[3] 该系统通过调用匹配 Activity(Activity B)的 onCreate() 方法并将其传递给 Intent,以此启动匹配 Activity。Intent 中包含的主要信息如下:
组件名称: Intent 的这一字段是一个 ComponentName 对象,您可以使用目标组件的完全限定类名指定此对象,其中包括应用的软件包名称。 例如, com.example.ExampleActivity。您可以使用 setComponent()、setClass()、setClassName() 或 Intent 构造函数设置组件名称。此字段也用来区分显/隐式Intent。
操作(action): 指定要执行的通用操作(例如,“查看”或“选取”)的字符串。您可以使用 setAction() 或 Intent 构造函数为 Intent 指定操作。
如果定义自己的操作,请确保将应用的软件包名称作为前缀。 例如:
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";数据(data): 引用待操作数据和/或该数据 MIME 类型的 URI(Uri 对象)。提供的数据类型通常由 Intent 的操作决定。创建 Intent 时,除了指定 URI 以外,指定数据类型(其 MIME 类型)往往也很重要。例如,能够显示图像的 Activity 可能无法播放音频文件,即便 URI 格式十分类似时也是如此。因此,指定数据的 MIME 类型有助于 Android 系统找到接收 Intent 的最佳组件。但有时,MIME 类型可以从 URI 中推断得出,特别当数据是 content: URI 时尤其如此。这表明数据位于设备中,且由 ContentProvider 控制,这使得数据 MIME 类型对系统可见。
要仅设置数据 URI,请调用 setData()。 要仅设置 MIME 类型,请调用 setType()。如有必要,您可以使用 setDataAndType() 同时显式设置二者。
注意:若要同时设置 URI 和 MIME 类型,请勿调用 setData() 和 setType(),因为它们会互相抵消彼此的值。请始终使用 setDataAndType() 同时设置 URI 和 MIME 类型。
类别(category): 您可以使用 addCategory() 指定类别。
CATEGORY_LAUNCHER 该 Activity 是任务的初始 Activity,在系统的应用启动器中列出。
以上列出的这些属性(组件名称、操作、数据和类别)表示 Intent 的既定特征。 通过读取这些属性,Android 系统能够解析应当启动哪个应用组件。
但是,Intent 也有可能会携带一些不影响其如何解析为应用组件的信息。 Intent 还可以提供:
Extra: 携带完成请求操作所需的附加信息的键值对。正如某些操作使用特定类型的数据 URI 一样,有些操作也使用特定的 extra。您可以使用各种 putExtra() 方法添加 extra 数据,每种方法均接受两个参数:键名和值。您还可以创建一个包含所有 extra 数据的 Bundle 对象,然后使用 putExtras() 将Bundle 插入 Intent 中。标志: 在 Intent 类中定义的、充当 Intent 元数据的标志。 标志可以指示 Android 系统如何启动 Activity(例如,Activity 应属于哪个任务),以及启动之后如何处理(例如,它是否属于最近的 Activity 列表)。Intent 过滤器是应用清单文件中的一个表达式,它指定该组件要接收的 Intent 类型。
匹配原则: Intent需要匹配多组intent-fliter中的任意一组,每一组包含action、data、category,即Intent同时满足这三者的过滤规则。
action的匹配原则: Intent中的action存在且必须和过滤规则中的其中一个action相同。(区分大小写)如果该过滤器未列出任何action,则 Intent 没有任何匹配项,因此所有 Intent 均无法通过测试。 但是,如果 Intent 未指定操作,则会通过测试(只要过滤器至少包含一个操作)。category的匹配原则: Intent中如果存在categary,那么所有的category都必须和intent-filter中相同。如果不含category,也可以匹配成功,因为在startActivity()中会默认给intent添加“android.intent.category.DEFAULT”。因此,要想acitivity接受隐式Intent,则必须在intent-filter中添加此category。注:Android 会自动将 CATEGORY_DEFAULT 类别应用于传递给 startActivity() 和 startActivityForResult() 的所有隐式 Intent。因此,如需 Activity 接收隐式 Intent,则必须将 “android.intent.category.DEFAULT” 的类别包括在其 Intent 过滤器中。
data的匹配原则: 与action类似,如果过滤规则中定义了data,那么Intent中则必须也要定义可匹配的data。data的语法结构如下: <data android:scheme="string" android:host="string" android:port="string" android:path="string" android:pathPrefix="string" android:pathPattern="string" android:mimeType="string"/>data由两部分组成:
mimeType: 指媒体类型URI: 路径结构< scheme >://< host >:< port >/[< path >|< pathPrefix >|< pathPattern >]
例如:content://com.example.project:200/folder/subfolder/etc
介绍一下每个数据的含义:
Scheme: URI的模式,如http、file、content(必须指定否则整个URI无效)Host:URI的主机名(必须指定否则整个URI无效)Port:URI的端口号Path/pathPattern/pathPrefix:表述路径信息,Path表示完整的路径信息;pathPattern也表示完整的路径信息,可包含通配符“*”,表示0到多个任意字符,pathPrefix表示路径的前缀信息原则:要求Intent中必须含有data数据,并且能完全匹配过滤规则中的都一个data。完全匹配指过滤规则中出现的data部分也出现在了Intent中的data。intent-filter中可以不指定URI,但是有默认值,URI的默认值为content和file。因此要匹配URI必须为content和file。
如下是一个过滤规则的实例:
<activity android:name="MainActivity"> <!-- This activity is the main entry, should appear in app launcher --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ShareActivity"> <!-- This activity handles "SEND" actions with text data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND_MULTIPLE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/vnd.google.panorama360+jpg"/> <data android:mimeType="image/*"/> <data android:mimeType="video/*"/> </intent-filter> </activity> action测试添加intent-filter:
<activity android:name=".Main2Activity"> <intent-filter> <action android:name="android.intent.action.EDIT"/> <action android:name="android.intent.action.CALL"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>MainActivity中添加:
btnAction.setOnClickListener { val intent = Intent() intent.action = Intent.ACTION_EDIT startActivity(intent) }点击按钮成功跳转。
category测试 添加intent-filter: <activity android:name=".Main2Activity"> <intent-filter> <action android:name="android.intent.action.EDIT"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="com.wdl.intentfliter.category.a"/> <category android:name="com.wdl.intentfliter.category.b"/> <category android:name="com.wdl.intentfliter.category.c"/> </intent-filter> </activity>MainActivity中添加:
btnAction.setOnClickListener { val intent = Intent() intent.action = Intent.ACTION_EDIT intent.addCategory("com.wdl.intentfliter.category.b") intent.addCategory("com.wdl.intentfliter.category.a") intent.addCategory("com.wdl.intentfliter.category.c") startActivity(intent) }点击按钮成功跳转。
data测试 添加intent-filter: <activity android:name=".Main2Activity"> <intent-filter> <action android:name="android.intent.action.EDIT"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="com.wdl.intentfliter.category.a"/> <category android:name="com.wdl.intentfliter.category.b"/> <category android:name="com.wdl.intentfliter.category.c"/> <data android:mimeType="text/plain"/> </intent-filter> </activity>MainActivity中:
btnAction.setOnClickListener { val intent = Intent() intent.action = Intent.ACTION_EDIT intent.setDataAndType(Uri.parse("file://test"),"text/plain") intent.addCategory("com.wdl.intentfliter.category.b") intent.addCategory("com.wdl.intentfliter.category.a") intent.addCategory("com.wdl.intentfliter.category.c") startActivity(intent) }上面的例子中存在Android 7.0 FileProvider适配问题,请自行解决。
注意:若要同时设置 URI 和 MIME 类型,请勿调用 setData() 和 setType(),因为它们会互相抵消彼此的值。请始终使用 setDataAndType() 同时设置 URI 和 MIME 类型。
为了避免在intent-fliter匹配过程中出现找不到Activity导致的异常闪退问题,提供了2中判断方法:
PackageManager的resolveActivity方法Intent中的resolveActivity方法 如果以上两种方法找不到匹配的Activity,就会返回null。防止出现异常。 btnAction.setOnClickListener { val intent = Intent() intent.action = Intent.ACTION_EDIT intent.type = "text/plain" intent.addCategory("com.wdl.intentfliter.category.b") intent.addCategory("com.wdl.intentfliter.category.a") intent.addCategory("com.wdl.intentfliter.category.c") packageManager.resolveActivity(intent, MATCH_DEFAULT_ONLY)?.let { startActivity(intent) } }MATCH_DEFAULT_ONLY: 这个标记位含义是仅仅匹配那些声明了 < category android:name=“android.intent.category.DEFAULT”/>的Activity。
另外PackageManager还提供了queryIntentActivities方法,返回所有匹配成功的Activity。