您的位置:首页 > 移动开发 > Android开发

Intent和Intent过滤器

2017-11-07 21:51 246 查看

一 Intent

1.1 Intent概念

Intent:用于组件间传递消息的对象,是Android组件之间进行交互的重要方式之一。主要在三个地方用的比较多:启动Activity、启动服务、传递广播。

启动Activity:

通过将Intent传递给startActivity(),您可以启动新的 Activity实例。Intent描述了要启动的Activity,并携带了任何一些必要的数据。如果您希望在Activity完成后收到结果,请调用startActivityForResult()。在Activity 的onActivityResult()回调函数中会把需要返回的数据通过Intent传递回来。

启动Service服务:

通过将Intent传递给 startService(),您可以启动Service服务。Intent 描述了要启动的服务,并携带了一些任何必要的数据。如果Service服务旨在使用客户端-服务器接口,则通过将Intent传递给bindService(),您可以从其他组件绑定到此Service服务。

传递广播:

通过将Intent传递给 sendBroadcast()、sendOrderedBroadcast()或sendStickyBroadcast(),通过Intent携带需要传递的数据然后发送广播。

1.2 Intent种类

Intent被分为两种:显示Intent、隐式Intent。

显示Intent

按名称(完全限定类名)指定要启动的组件。 通常,您会在自己的应用中明确的知道您要启动的是哪个组件的时候使用显式Intent来启动该组件。(所有Service的启动都是显示Intent)

隐式Intent

不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来响应处理它。例如,如需要在地图上向用户显示位置,则可以使用隐式 Intent,请求另一具有此功能的应用在地图上显示指定的位置。

创建隐式Intent的时候,Android系统通过将Intent的内容(Action、Category、Data & MimeType)与在设备上其他应用的清单文件中组件声明的intent-filter 过滤器进行比较,通过一定的匹配规则找到要启动的组件,并向其传递Intent对象来启动组件。 如果找到了多个匹配的组件,则系统会显示一个对话框,让用户自己来选择要启动的组件。

为了确保应用的安全性,启动Service的时候,请始终使用显式Intent,且不要为服务声明 Intent过滤器。因为使用隐式Intent启动服务存在安全隐患,因为您无法确定哪些服务将响应Intent,且用户无法看到哪些服务已启动。从Android 5.0(API 级别21)开始,如果使用隐式 Intent 调用 bindService(),系统会引发异常。

隐式Intent使用还有一个特别要注意的点是,系统可能没有任何组件能处理startActivity()的隐式Intent。如果出现这种情况,则调用将会失败,且应用会崩溃。所以在调用startActivity()之前咱们得调用Intent对象的resolveActivity()验证是否有组件会接收该隐式Intent。如果结果不是空的,则至少有一个应用能够处理该 Intent,则可以安全调用 startActivity()。通用写法如下:

// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}


1.3 Intent的组成

组件名称(Component):

要启动的组件名称。这是可选项,但也是构建显式Intent的一项重要信息,这意味着Intent应当仅传递给由组件名称定义的应用组件。如果没有组件名称,则Intent是隐式的,且系统将根据其他Intent信息(例如,以下所述的操作、数据和类别)决定哪个组件应当接收 Intent。因此,如需在应用中启动特定的组件,则应指定该组件的名称。注:启动 Service 时,您应始终指定组件名称。 否则,您无法确定哪项服务会响应Intent,且用户无法看到哪项服务已启动。

Intent中这一字段是一个ComponentName 对象。可以使用 setComponent()、setClass()、setClassName()或Intent构造函数设置组件名称。

操作(Action):

指定Intent要执行的动作(例如,“查看”或“选取”)的字串。对于广播Intent,Action用于指定正在广播的操作。而且这个操作在很大程度上决定了其余Intent的构成,特别是数据和extra中包含的内容(根据不同的Action对extra的解析也不相同)。

可以使用setAction()或Intent构造函数为Intent 指定操作。(如果定义自己的操作,请确保将应用的软件包名称作为前缀)

数据(Data):

引用待操作数据和/或该数据MIME类型的URI(Uri 对象)。提供的数据类型通常由Intent的操作决定。例如,如果操作是 ACTION_EDIT,则数据应包含待编辑文档的URI。

创建Intent时,除了指定URI以外,指定数据类型(其 MIME 类型)往往也很重要。例如,能够显示图像的Activity可能无法播放音频文件,即便URI 格式十分类似时也是如此,因为指定了MIME,MIME可以区分是视频文件还是图像文件。因此,指定数据的MIME类型有助于Android系统找到接收Intent的最佳组件。但有时,MIME 类型可以从URI中推断得出,特别当数据是content:URI时尤其如此。这表明数据位于设备中,且由ContentProvider控制,这使得数据MIME类型对系统可见。

仅设置数据URI,请调用setData()。要仅设置MIME 类型,请调用setType()。如有必要,您可以使用 setDataAndType()同时显式设置二者。(setData()和setType()不能同时使用,会相互抵消。想同时设置两者一定要调用setDataAndType())

类别(Category):

一个包含应处理Intent组件类型的附加信息的字符串。 您可以将任意数量的类别描述放入一个Intent中,但大多数Intent均不需要类别。

可以使用addCategory()来添加类别。

额外数据(Extra):

携带完成请求操作所需的附加信息的键值对。

可以使用各种putExtra()方法添加extra数据,每种方法均接受两个参数:键名和值。您还可以创建一个包含所有extra数据的Bundle对象,然后使用 putExtras()将Bundle插入Intent 中。

标志(Flags):

在Intent类中定义的、充当Intent元数据的标志。标志可以指示Android系统如何启动Activity(例如,Activity应属于哪个任务),以及启动之后如何处理(例如,它是否属于最近的Activity列表)。关于Intent Flags更加详细的内容可以看看 Android任务和返回栈简单总结里面有对Intent Flags做一些简单的总结。

二 Intent过滤器

IntentFilter是Intent过滤器,那IntentFilter是如果过滤匹配Intent的呢。

动作(Action)匹配规则:

action是一个字符串,如果Intent(startActivity的Intent)指明了action,则目标组件的IntentFilter(ManifestAndroid.xml里面activity intent-filter标签)就必须包含这个action。(每个Intent只能指定一个action,重复设置会覆盖之前的action)。

种类(Category)匹配规则:

ategory也是一个字符串,但是他和action有点不同的是,Intent中可以包含多个category所以当Intent中有多个category的时候,所有的category都必须在则目标组件的IntentFilter标签里面找到。

数据(Data)匹配规则:

data由两部分组成:mimeType、URI。

mimeType(每个Intent只能设置一个mimeType)的匹配规则有以下几种情况:如果目标组件IntentFilter里面设置了mimeType,那么Intent也必须设置相同的mimeType才能匹配上。如果目标组件IntentFilter里面没有设置mimeType,那么Intent里面也不能设置mimeType才能匹配上。

URI由scheme、host、port、path | pathPattern | pathPrefix4部分组成。一个完整的URI如下:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]


URI(每个Intent只会有一个URI)的匹配规则:无论是scheme、host、port还是path|pathRrefix|pathPattern如果目标组件IntentFilter设置了(在IntentFilter他们都可能设置多个),那么Intent也必须设置并且还得在IntentFilter找到相应的。

URI匹配有两条规则咱们还得注意:

1. 如果目标组件IntentFilter的scheme没有设置,那么目标组件IntentFilter中 host、port、path|pathRrefix|pathPattern属性均无效不会去匹配。

2. 如果目标组件IntentFilter的host没有设置,那么目标组件IntentFiltersche data中设置的port、path|pathRrefix|pathPattern均无效不会去匹配。

关于InterFilter Data的匹配有一点我们特别要注意。不管AndroidManifest.xml文件组件的InterFilter标签里面设置了多少个data。最后都是会柔到一起去的,shceme、hoset、path等等都放到一个list里面去。只要我们Intent相应设置的shceme、hoset、path在对应的list里面能找到就算匹配上了。可能说起来比较空洞。我们举一个具体的实例来说明。

<activity
android:name=".TwoActivity"
android:exported="true">
<intent-filter>
<action android:name="com.tuacy.singletasktwo.TEST" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="test" android:host="www.google.com" android:port="80"/>
<data android:scheme="test2"/>
<data android:mimeType="text/*" />
</intent-filter>
</activity>


如下的隐式Intent也是可以启动到上诉声明的Activity的。

Intent intent = new Intent("com.tuacy.singletasktwo.TEST");
Uri data = Uri.parse("test2://www.google.com:80");
intent.setDataAndType(data, "text/*");
startActivity(intent);


你可能注意到了隐式Intent里面Uri写的是test2://www.google.com:80。注意是test2哦,不是test哦,不是同一个data给的哦。其实根据上面AndroidManifest.xml文件组件的InterFilter标签最终会scheme解析到一个list里面去这个list包含test和test1。Intent给定的scheme能在这个list里面找到。

最后我们总结下Intent的匹配规则(主要是正对Activity的匹配)更加详细的内容请参考Intent匹配过程源码简单分析

如果目标组件IntentFilter节点没有指定action,那么任何隐式的Intent都匹配过不到给该组件。

如果目标组件IntentFilter节点可以隐式匹配到,不管三七二十一您就就加上android.intent.category.DEFAULT的category肯定不会有错的。

如果Intent中有多个category,那么这个Intent的所有的category在目标组件IntentFilter节点中全部找到才算匹配通过。

如果Intent中没有指定Action,如果想这个Intent能匹配到目标组件IntentFilter。那么这个Intent至少得指定data 或者type中的一个。要不能也是匹配不到的。

如果目标组件IntentFilter没有设置mimeType,那么Intent里面也不能设置mimeType才能匹配上。

如目标组件IntentFilter里面设置了mimeType,那么Intent也必须设置相同的mimeType才能匹配上。

如果目标组件IntentFilter里面没有设置scheme,那么目标组件IntentFilter data中设置的host,port,pathRrefix,pathPattern属性都没有任何意义。这个时候如果想匹配上这个Intent Filter的组件那么Intent要么不设置scheme,要么scheme设置成“”、”content”、”file”。

如果目标组件IntentFilter里面没有设置host,那么目标组件IntentFilter data中设置的port,path,pathRrefix,pathPattern均没有意义。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息