Android-0.Intent及Intent Filter简介


官方文档: https://developer.android.google.cn/guide/components/intents-filters

Intent的用途

  1. startActivity()startActivityForResult()方法启动ActivityIntent对象包含了要启动的Activity的信息及其他必要的数据。
  2. startService()bindService()方法启动ServiceIntent对象包含了要启动的Service的信息及其他必要的数据。
  3. sendBroadcast()sendOrderedBroadcast()sendStickyBroadcast()方法发送广播。

Intent的类型

显式的Intent

如果Intent中明确包含了要启动的组件的完整类名(包名及类名),那么这个Intent就是显式的。

隐式的Intent

反之就是隐式的, 一般,隐式intent不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理它。
例如,你想在地图上给用户显示一个位置,但是你的App又不支持地图展示,这时候你可以将位置信息放入到一个Intent中,然后给它指定相应的action,通过这样隐式的Intent请求其他地图类型的App(例如Google Map、百度地图等)来在地图中展示一个指定的位置。

模块解藕示例:https://www.cnblogs.com/xjx22/p/5551034.html

当创建了一个隐式Intent时,Android系统会将该隐式Intent所包含的信息与设备上其他所有AppAndroidManifest.xml中的<intent-filter>进行对比过滤,从中找出满足能够接收处理该隐式IntentApp和对应的组件。如果有多个App中的某个组件都符合条件,那么Android会弹出一个对话框让用户选择需要启动哪个App

其实同样可以理解为监听者模式, 而隐式Intent的调用就是一个广播查找调用。

Intent的组成

Android可以根据Intent所携带的信息去查找要启动的组件,启动的组件根据Intent携带的一些数据信息做相应的处理。
Intent由6部分信息组成:Component NameActionDataCategoryExtrasFlags

  1. Component NameActionDataCategory、决定了Android会启动哪个组件,其中Component Name用于显式IntentIntentActionDataCategoryExtrasFlags用于在隐式Intent
  2. Extras里面包含了具体的用于组件实际处理的数据信息。
  3. FlagsIntent的元数据,决定了Android对其操作的一些行为。

Component name(组件名)

要启动的组件名称。如果你想使用显式的Intent,那么你就必须指定该参数,一旦设置了component name,Android会直接将Intent传递给组件名所指定的组件去启动它。

需要注意的是,当启动Service的时候,你应该总是指定Component Name。否则,你不确定最终哪个App的哪个组件被启动了,并且用户也看不到哪个Service启动了。

component nameIntent中对应的fieldComponentName对象,你可以通过要启动的组件的完整类名(包括应用的包名)指定该值,例如com.example.ExampleActivity。你可以通过IntentsetComponent()方法、setClass()方法、setClassName()方法或Intent的构造函数指定component name

Action(操作)

表示了要执行操作的字符串。比如查看选择,其对应着<intent-filter>中的<action />标签.

预定义的具有通用意义的action

  1. Intent.ACTION_VIEW 值为 “android.intent.action.VIEW”,当你有一些信息想通过其他Activity展示给用户的时候,你就可以将Intentaction指定为ACTION_VIEW,比如在一个图片应用中查看一张图片,或者在一个地图应用中展现一个位置。
  2. Intent.ACTION_SEND 值为”android.intent.action.SEND”,该action常用来做“分享”使用,当你有一些数据想通过其他的App(例如QQ、微信、百度云等)分享出去的时候,就可以使用此action构建Intent对象,并将其传递给startActivity()方法,由于手机上可能有多个App的Activity均支持ACTION_SEND这一action,所以可能出现多个APP供你选择。

自定义action
请确保将应用的软件包名称作为前缀,例如:<action android:name="com.demoBActivity.action" />

你可以指定你独有的action以便于你的App中的Intent使用或其他App中通过Intent调用你的App中的组件。

你可以通过调用intentsetAction()方法或在Intent的构造函数中指定intentaction

Data(数据)

此处所说的Intent中的data指的是Uri对象和数据的MIME类型,对应着<intent-filter>中的<data />标签。

一个完整的Uri由schemehostportpath组成,格式是<scheme>://<host>:<port>/<path>。例如content://com.example.project:200/folder/subfolder/etc

Uri就像一个数据链接,组件可以根据此Uri获得最终的数据来源。通常将Uri和action结合使用,比如我们将action设置为ACTION_VIEW,我们应该提供将要被编辑修改的文档的Uri。

当创建了一个Intent对象的时候,除了指定Uri之外,指定数据的MIME类型也很重要。

例如,一个Activity能够显示图片,但是不能够播放视频,显示图片的Uri和播放视频的Uri可能很类似,为了不让Android误将一个含有视频Uri的Intent对象传递给一个只能显示图片的Activity,我们需要在该Activity<intent-filter>中指定MIME类型为图片(例如<data android:mimeType="image/*" ... />)并且还要给Intent对象设置对应的图片类型的MIME,这样Android就会基于Uri和MIME类型将Intent传递给符合条件的组件。

有个特例,如果Uri使用的是content:协议,那么这就说明Uri所提供的数据将来自于本地设备,即数据由ContentProvider提供,这种情况下Android会根据Uri自动推断出MIME类型,此种情况我们无需再自己指定MIME类型。

需要注意的是,如果你想要同时设置数据的Uri和MIME类型,不要先后调用Intent对象的setData()方法和setType()方法,因为setData()方法和setType()是互斥的,即如果调用了setData()方法,会将Intent中已经通过setType()方法设置的MIME类型重置为空。如果调用了setType()方法,会将Intent中已经通过setData()方法设置的Uri重置为空。所以在需要同时设置数据的Uri和MIME类型的时候,一定要调用Intent对象的setDataAndType()方法,而不是分别调用setData()方法和setType()方法。

Category (类别)

category包含了关于组件如何处理Intent的一些其他信息,虽然可以在Intent中加入任意数量的category,但是大多数的Intent其实不需要category

以下是一些常见的category

  1. CATEGORY_BROWSABLE 目标 Activity 允许本身通过网络浏览器启动,以显示链接引用的数据,如图像或电子邮件。
  2. CATEGORY_LAUNCHER 用于标识Activity是某个App的入口Activity

Extras

extras,顾名思义,就是额外的数据信息,Intent中有一个Bundle对象存储着各种键值对,接收该Intent的组件可以从中读取出所需要的信息以便完成相应的工作。有的Intent需要靠Uri携带数据,有的Intent是靠extras携带数据信息。

你可以通过调用Intent对象的各种重载的putExtra(key, value)方法向Intent中加入各种键值对形式的额外数据。你也可以直接创建一个Bundle对象,向该Bundle对象传入很多键值对,然后通过调用Intent对象的putExtras(Bundle)方法将其设置给Intent对象中去。

例如,你创建了一个actionACTION_SEND用于发送电子邮件的 Intent 时,
Intent.EXTRA_EMAIL 指定“目标”收件人,用Intent.EXTRA_SUBJECT 指定“主题”。

Intent 类将为标准化的数据类型指定多个 EXTRA_* 常量。如需声明自己的 extra 键(对于应用接收的 Intent),请确保将应用的软件包名称作为前缀。 例如::static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";

Flags (标志)

Intent 类中定义的、充当 Intent 元数据的标志。 标志可以指示 Android 系统如何启动 Activity(例如,Activity 应属于哪个任务),以及启动之后如何处理(例如,它是否属于最近的 Activity 列表)。。更多信息可参见IntentsetFlags()方法。

隐式Intent使用示例

例如,你有一段文本信息,想通过其他App分享出去,示例代码如下:

Intent sendIntent = new Intent();
// 设置action, action对隐式Intent来说是非常重要的
sendIntent.setAction(Intent.ACTION_SEND);
// 设置数据的MIME类型为纯文本类型
sendIntent.setType("text/plain");
// 设置额外的数据
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);

// 获取包管理器
PackageManager pm = getPackageManager();
// 先判断系统中有没有潜在的App的Activity支持对该sendIntent的接收与处理
if (pm.resolveActivity(sendIntent, 0) != null) {
    startActivity(sendIntent);
}

上面的代码中,我们构建了一个隐式的Intent对象。我们设置了action的值为Intent.ACTION_SENDaction对隐式Intent来说是非常重要的。然后我们将intent的数据的MIME类型设置为纯文本类型(“text/plain”),告知Android我们的Intent持有的是文本类型的数据。最后我们将实际的文本数据通过putExtra()方法作为额外数据设置进去。

需要注意的是,在构建好了Intent对象之后,我们没有立即执行startActivity(sendIntent)方法,而是将sendIntent作为参数传递给了PackageManagerresolveActivity()方法中,该方法会让Android根据该sendIntent找到潜在的适合启动的组件的信息,并以ResolveInfo类的对象的形式返回结果,如果返回null,表示当前系统中没有任何组件可以接收并处理该sendIntent。如果返回不是null,就表明系统中至少存在一个组件可以接收并处理该sendIntent,只有在这种情况下,我们才会执行代码startActivity(sendIntent),在通过intent启动组件之前先判断要启动的组件存不存在是个良好的编程习惯,因为如果系统中不存在支持你的intent的组件,那么当你调用startActivity()startService()bindService()等方法的时候,Android就会抛出异常。

强制用户使用应用选择器

如果有多个应用响应隐式 Intent,则用户可以选择要使用的应用,并将其设置为该操作的默认选项。 如果用户可能希望今后一直使用相同的应用执行某项操作(例如,打开网页时,用户往往倾向于仅使用一种网络浏览器),则这一点十分有用。

但是如果用户不想每次都用同一个默认App处理这样的情形怎么办呢?这时候我们可以在代码中明确地使用App选择对话框,比如我们的App执行一个action为ACTION_SEND的分享功能时,我们想让用户分享自己数据的代码,但是我们不确定用户想通过哪个App去分享,我们想每次都弹出App选择对话框让用户决定想通过哪个App分享,示例代码如下所示:

Intent sendIntent = new Intent(Intent.ACTION_SEND);
...

String title = "请选择想通过哪个App分享数据";

// 验证是否有App能够接收并处理sendIntent
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    // 根据sendIntent创建一个需要显示App选择对话框的intent对象
    Intent chooserIntent = Intent.createChooser(sendIntent, title);
    // 我们使用chooserIntent作为startActivity()方法的参数,而非sendIntent
    startActivity(chooserIntent);
}

首先我们创建了我们原始的sendIntent,并对其设置action等相关信息,然后我们将sendIntent传递给了Intent.createChooser()方法中,创建了另一个chooserIntent。后面我们通过调用Intent.resolveActivity(PackageManager)方法判断系统中是否有App能够接收并处理sendIntent,该方法与上面之前提到过的PackageManagerresolveActivity()方法是等价的。最后我们使用chooserIntent作为startActivity()方法的参数,而非sendIntentchooserIntent会让Android系统强制显示用户选择App处理Intent的界面。

Intent对象与Intent Filter过滤匹配过程

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

  1. intent中的action
  2. intent中的category
  3. intent中的data(包含Uri以及data的MIME类型)

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

Action测试

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

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <action android:name="com.ispring.action.ACTION_TEST2" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

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

intent对象设置了action

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

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

<intent-filter>
   <action android:name="com.ispring.action.ACTION_TEST1" />
   <action android:name="com.ispring.action.ACTION_TEST2" />
   <category android:name="android.intent.category.DEFAULT" />
   <data android:scheme="ispring" android:host="blog.csdn.net" />
</intent-filter>

1.下面的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>中包含该intentactioncom.ispring.action.ACTION_TEST1

2.下面的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>中不包含该intentactioncom.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);

1.上面的intent对象可以通过如下的<intent-filter>

<intent-filter>
    <action android:name="com.csdn.action.ACTION_XXX" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="ispring" android:host="blog.csdn.net" />
</intent-filter>

2.上面的intent对象无法通过如下的<intent-filter>

<intent-filter>
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="ispring" android:host="blog.csdn.net" />
</intent-filter>

总结

总结起来有两点结论:

  1. 要想让intent对象通过action测试,那么<intent-filter>中声明的action不能为空且要包含intent对象中的action值(如果intentaction值不为空的话)。
  2. 如果<intent-filter>没有声明任何action,那么所有的intent的对象(即无论intent如何配置)都无法通过<intent-filter>action测试。

Category测试

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

<intent-filter>
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    ...
</intent-filter>

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

intent对象至少有一个category

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

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

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="com.ispring.category.TEST1" />
    <category android:name="com.ispring.category.TEST2" />
</intent-filter>

1.以下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.TEST1com.ispring.category.TEST2

2.以下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.TEST1category,而并未包含值为com.ispring.category.TEST3category

intent对象不包含任何category

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

此处需要特别说明的是,我们在上面所有的示例中,都给Activity<intent-filter>添加了值为android.intent.category.DEFAULTcategory,这是因为当我们把一个隐式的intent传递给startActivity()startActivityForResult()方法时,Android会自动给该隐式intent添加值为android.intent.category.DEFAULTcategory,所以为了能让<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.DEFAULTcategory

Data测试

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

<intent-filter>
    <data android:mimeType="video/mpeg" android:scheme="http" ... />
    <data android:mimeType="audio/mpeg" android:scheme="http" ... />
    ...
</intent-filter>

每个<data />标签都可以指定一个URI结构以及data的MIME类型。一个完整的URI由schemehostportpath组成,其结构如下所示:<scheme>://<host>:<port>/<path>
其中scheme既可以是Android中常见的协议,也可以是我们自定义的协议。Android中常见的协议包括content协议http协议file协议等,自定义协议可以使用自定义的字符串。

如下是一个content协议的URI:

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

在该URI中,schemecontenthostcom.example.projectport200pathfolder/subfolder/etc

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

ispring://blog.csdn.net/hgy 

在该URI中,schemeispringhostblog.csdn.net,没有明确设定portpathhgy

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

  1. 如果没有指定scheme,那么host参数会被忽略
  2. 如果没有指定host,那么port参数会被忽略
  3. 如果schemehost都没有指定,path参数会被忽略

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

  1. 如果<intent-filter>中只指定了scheme,那么所有带有该sheme的URI都能匹配到该<intent-filter>
  2. 如果<intent-filter>中只指定了schemeauthorityauthority包括hostport两部分)而没有指定path,那么所有具有相同schemeauthority的URI都能匹配到该<intent-filter>,而不用考虑path为何值。
  3. 如果<intent-filter>中同时指定了schemeauthoritypath,那么只有具有相同schemeauthoritypath的URI才能匹配到该<intent-filter>

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

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

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

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

intent对象不包含URI和MIME类型

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

例如我们有如下intent对象:

Intent intent = new Intent();
intent.setAction("com.ispring.action.ACTION_TEST1");

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

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

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

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="ispring" />
</intent-filter>

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

这种情况下,只有当intent对象的URI匹配到了<intent-filter>中的URI格式,并且<intent-filter>没有指定MIME类型的时候才能通过data测试。需要注意的是,这里所说的<intent-filter>没有指定MIME类型的情形指的是<intent-filter>中所有的<data />标签都没有指定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/hgy413");
intent.setData(uri);

1.上面的intent能通过如下的<intent-filter>的data测试:

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="ispring" android:host="blog.csdn.net" />
</intent-filter>

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

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="ispring" android:host="blog.csdn.net" />
    <data android:scheme="hgy" android:host="8080" />
</intent-filter>

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

3.上面的intent对象无法通过以下<intent-filter><data />标签测试:

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="text/plain" android:scheme="ispring" android:host="blog.csdn.net" />
</intent-filter>

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

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

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="ispring" android:host="blog.csdn.net" />
    <data android:mimeType="text/plain" />
</intent-filter>

上面的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>中所有<data />标签都没有指定URI,即整个<intent-filter>中完全没有android:schemeandroid:hostandroid:port以及android:path,理解这点很重要,大家在下面的几个示例中可以体会到这点。

例如有如下intent对象:

Intent intent = new Intent();
intent.setAction("com.ispring.action.ACTION_TEST1");
intent.setType("text/plain");

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

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="text/plain" />
</intent-filter>

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

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="image/*" />
    <data android:mimeType="text/plain" />
</intent-filter>

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

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

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="text/plain" android:scheme="ispring" />
</intent-filter>

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

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

<intent-filter>
    <action android:name="com.ispring.action.ACTION_TEST1" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="text/plain"  />
    <data android:scheme="ispring" />
</intent-filter>

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

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

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

  1. 对于MIME测试:如果intent的MIME类型能够匹配<intent-filter>中列出的某一个<data />标签中的MIME类型值,那么MIME类型测试就通过了。
  2. 对于URI测试:
    又细分两种情况,满足下面的任何一种情况都可以通过URI测试。
    (1).如果intent的URI格式能够匹配<intent-filter>中列出的某一个<data />中的URI,那么URI测试就通过了。
    (2). 如果intent的URI是content:协议或file:协议,并且整个<intent-filter>的所有<data />标签中都没有指定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/hgy");
String type = "text/plain";
intent.setDataAndType(uri, type);

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

<intent-filter>
      <action android:name="com.ispring.action.ACTION_TEST1" />
      <category android:name="android.intent.category.DEFAULT" />
      <data android:scheme="ispring" android:host="blog.csdn.net" />
      <data android:mimeType="text/plain"  />
</intent-filter>

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

<intent-filter>
      <action android:name="com.ispring.action.ACTION_TEST1" />
      <category android:name="android.intent.category.DEFAULT" />
      <data android:scheme="ispring" android:host="blog.csdn.net" android:port="8080" />
      <data android:mimeType="text/plain"  />
</intent-filter>

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

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

<intent-filter>
      <action android:name="com.ispring.action.ACTION_TEST1" />
      <category android:name="android.intent.category.DEFAULT" />
      <data android:scheme="ispring" android:host="blog.csdn.net" />
      <data android:mimeType="image/*"  />
</intent-filter>

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);

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

<intent-filter>
      <action android:name="com.ispring.action.ACTION_TEST1" />
      <category android:name="android.intent.category.DEFAULT" />
      <data android:scheme="ispring" />
      <data android:mimeType="text/plain"  />
</intent-filter>

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

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

<intent-filter>
      <action android:name="com.ispring.action.ACTION_TEST1" />
      <category android:name="android.intent.category.DEFAULT" />
      <data android:mimeType="text/plain"  />
</intent-filter>

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

参考:
https://developer.android.google.cn/guide/components/intents-filters
https://blog.csdn.net/iispring/article/details/48481793

猜你喜欢

转载自blog.csdn.net/hgy413/article/details/85266093