Android官方文档—APP组件(Intents and Intent Filters)(概述)

意图和意图过滤器

Intent是一个消息对象,您可以使用它从另一个组件中请求动作。尽管意图以多种方式实现组件之间的通信,但有三个基本用法:

  • 启动activity

活动表示应用程序中的单个屏幕。您可以通过将Intent传递给startActivity()来启动Activity的新实例。 Intent描述了要启动的activity并携带一些必要的数据。

如果要在activity结束时从activity中收到结果,请调用startActivityForResult()。您的activity在onActivityResult()回调中将结果作为单独的Intent对象接收。有关更多信息,请参阅Activities指南。

  • 启动service

服务是在没有用户界面的情况下在后台执行操作的组件。您可以通过将Intent传递给startService()来启动服务以执行一次性操作(例如下载文件)。 Intent描述了要启动的服务并携带一些必要的数据。

如果服务是使用client-server接口设计的,则可以通过将Intent传递给bindService()来绑定到另一个组件的服务。有关更多信息,请参阅Services指南。

  • 发送广播

广播是任何应用都可以接收的消息。系统为系统事件提供各种广播,例如系统启动或设备开始充电时。您可以通过将Intent传递给sendBroadcast(),sendOrderedBroadcast()或sendStickyBroadcast()来向其他应用程序发送广播。

Intent类型


两种类型的Intent:

  • 显式Intent指定按名称开始的组件(完全限定的类名)。您通常会使用显式意图在您自己的应用中启动组件,因为您知道要启动的活动或服务的类名。例如,响应用户操作启动新的activity或启动服务以在后台下载文件。
  • 式Intent隐式意图不指定特定组件,而是声明要执行的操作,这允许来自另一个应用程序的组件处理它。例如,如果要向用户显示地图上的位置,则可以使用隐式意图请求另一个可以在地图上显示位置的应用程序。

当您使用显式意图创建启动activity或service时,系统会立即启动Intent对象中指定的应用程序组件。当您创建隐式intent时,Android系统会通过将intent的内容与设备上其他应用程序的manifest文件中声明的intent过滤器进行比较来找到适当的组件。如果intent与intent过滤器匹配,则系统启动该组件并将其传递给Intent对象。如果多个intent过滤器兼容,系统将显示一个对话框,以便用户可以选择要使用的应用程序。

意图过滤器是应用程序清单文件中的表达式,用于指定组件要接收的意图类型。例如,通过为活动声明一个意图过滤器,您可以让其他应用程序以某种意图直接启动您的活动。同样,如果您没有为活动声明任何意图过滤器,那么只能使用显式意图启动它。

警告:为确保您的应用程序安全,在启动service时始终使用明确的意图,并且不要为您的service声明意图过滤器。使用隐式意图启动service存在安全隐患,因为您无法确定哪些service将响应意图,并且用户无法查看启动哪个service。从Android 5.0(API级别21)开始,如果使用隐式intent调用bindService(),系统将引发异常。

图1。 如何通过系统传递隐式意图以启动另一个活动的说明:[1]活动A创建一个带有动作描述的Intent并将其传递给startActivity()。 [2] Android系统在所有应用中搜索与意图匹配的意图过滤器。当找到匹配时,[3]系统通过调用其onCreate()方法并将其传递给Intent来启动匹配活动(Activity B)。

创建Intent


Intent对象携带Android系统用于确定启动哪个组件的信息(例如应该接收意图的确切组件名称或组件类别),并提供接收组件用于正确执行操作的信息(例如要采取的操作和要处理的数据)。

Intent中包含的主要信息如下:

Component name

要启动的组件名称。

这是可选的,但它是使显式意图的关键信息,这意味着意图仅传递给在app明确给定名称的组件。如果没有组件名称,则意图是隐式的,系统根据其他意图信息(例如下面描述的操作,数据和类别)决定哪个组件应该接收这个意图。因此,如果您需要在应用程序中启动特定组件,则应指定组件名称。

注意:启动服务时,应始终指定组件名称。否则,您无法确定哪些服务将响应意图,并且用户无法查看哪个服务启动。

ComponentName对象是Intent的一个字段,您可以使用目标组件的完全限定类名指定该对象,包括应用程序的包名称。例如,com.example.ExampleActivity。您可以使用setComponent(),setClass(),setClassName()或Intent构造函数设置组件名称。

Action

一个字符串,指定要执行的一般操作(例如查看或选取)。

在广播意图的情况下,这是触发并广播的动作。该操作很大程度上决定了意图的其余部分是如何构建的 - 特别是数据和附加内容中包含的内容。

您可以指定自己的Action以供应用程序中的意图使用(或供其他应用程序用于调用自己应用程序中的组件),但通常应使用由Intent类或其他框架类定义的Action常量。以下是启动活动的一些常见Action:

ACTION_VIEW

当您拥有活动可以向用户显示的某些信息时,例如要在图库应用中查看的照片或要在地图应用中查看的地址,请将具有此Action的intent传入startActivity()。

ACTION_SEND

也称为“共享”意图,当您拥有用户可以通过其他应用程序(例如电子邮件应用程序或社交共享应用程序)共享的某些数据时,请将具有此Action的intent传入startActivity()。

有关定义通用action的更多常量,请参阅Intent类参考。其他操作在Android框架的其他位置定义,例如在“设置”中,用于在系统的“设置”应用中打开特定屏幕的action。

您可以使用setAction()或Intent构造函数指定intent的action。

如果您定义自己的action,请确保将应用程序的包名称作为前缀。例如:

static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";

Data

URI(一个Uri对象),它标识要作用的数据和/或该数据的MIME类型。提供的数据类型通常由意图的action决定。例如,如果操作是ACTION_EDIT,则数据应包含要编辑的文档的URI。

在创建intent时,除了URI之外,通常还需要指定数据类型(其MIME类型)。例如,即使URI格式可能类似,但能够显示图像的activity可能无法播放音频文件。因此,指定数据的MIME类型有助于Android系统找到接收意图的最佳组件。但是,有时可以从URI推断MIME类型 - 特别是当数据是content: URI时,表示数据位于设备上并由ContentProvider控制,这使得数据MIME类型对系统可见。

要仅设置数据URI,请调用setData()。要仅设置MIME类型,请调用setType()。如有必要,可以使用setDataAndType()明确设置它们。

警告:如果要同时设置URI和MIME类型,请不要调用setData()和setType(),因为它们都会使另一个的值无效。应当使用setDataAndType()来设置URI和MIME类型。

Category

一个字符串,包含有关应处理意图的组件类型的其他信息。可以在意图中放置任意数量的类别描述,但大多数意图不需要类别。以下是一些常见类别:

CATEGORY_BROWSABLE

目标activity允许自己由Web浏览器启动,以显示由链接引用的数据,例如图像或电子邮件消息。

CATEGORY_LAUNCHER

activity是任务的初始活动,并列在系统的应用程序启动器中。

有关完整的类别列表,请参阅Intent类说明。

您可以使用addCategory()指定类别。

上面列出的这些属性(组件名称,操作,数据和类别)表示intent的定义特征。通过读取这些属性,Android系统能够解析应该启动应用程序的哪个组件。

但是,意图还可以携带不影响如何解析应用程序组件的其他信息。意图还可以提供:

Extras

带有完成所请求操作所需的附加信息的键值对。正如某些操作使用特定类型的数据URI一样,某些操作也使用特定的附加功能。您可以使用各种putExtra()方法添加额外数据,每个方法都接受两个参数:键名和值。您还可以使用所有额外数据创建Bundle对象,然后使用putExtras()将Bundle插入Intent中。例如,在创建使用ACTION_SEND发送电子邮件的意图时,您可以使用EXTRA_EMAIL键指定“收件人”,并使用EXTRA_SUBJECT键指定“主题”。

Intent类为标准化数据类型指定了许多EXTRA_ *常量。如果您需要声明自己的额外Key(用于您的应用收到的意图),请务必将您应用的包名称作为前缀。例如:

static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";

Flags

Intent类中定义的标志,用作intent的元数据。flags可以指示Android系统如何启动activity(例如,activity应该属于哪个task)以及如何在启动activity后对其进行处理(例如,它是否属于最近activity的列表)。

有关更多信息,请参阅setFlags()方法

显式意图举例

显式意图是您用于启动特定应用程序组件的意图,例如应用程序中的特定activity或service。要创建显式意图,请定义Intent对象的组件名称 以及意图可选的其他属性。

例如,如果您在应用程序中构建了一个名为DownloadService的服务,旨在从Web下载文件,则可以使用以下代码启动它:

// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

Intent(Context,Class)构造函数为应用程序Context和组件提供Class对象。因此,此意图显式启动应用程序中的DownloadService类。

有关构建和启动服务的详细信息,请参阅“Services指南”。

隐式意图举例

隐式intent指定可以调用设备上能够执行本次操作的任何应用程序。当您的应用无法执行此操作时,但其他应用可能可以,使用隐式意图很有用,您希望让用户来选择要使用的执行此操作的应用。

例如,如果您希望用户与其他人分享某些内容,可以使用ACTION_SEND Action创建意图,并添加指定要分享内容的附加内容。当您使用该意图调用startActivity()时,用户可以选择一个应用程序去分享这些内容。

注意:用户可能没有安装可以处理您发送到startActivity()的隐式意图的应用程序。如果发生这种情况,调用将失败,您的应用将崩溃。要验证是否有activity接收intent,请在Intent对象上调用resolveActivity()。如果结果为非null,则至少有一个应用程序可以处理意图,并且可以安全地调用startActivity()。如果结果为null,则不应使用此intent,如果可能,应禁用发出此intent的功能。

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

 注意:In this case, a URI is not used, but the intent's data type is declared to specify the content carried by the extras

当调用startActivity()时,系统会检查所有已安装的应用程序,以确定哪些应用程序可以处理此类意图(使用ACTION_SEND操作并带有“text / plain”数据的意图)。如果只有一个应用程序可以处理它,那么该应用程序会立即打开并传递该意图。如果多个活动接受意图,系统将显示一个对话框,以便用户可以选择要使用哪一个应用程序接收该意图。

App 选择器

图2,app选择器对话框。

当有多个应用程序响应您的隐式意图时,用户可以选择要使用的应用程序,并使该应用程序成为该Action的默认选择。这在执行用户可能希望以后使用相同应用程序打开该Action时非常有用,例如在打开网页时(用户通常只喜欢一个Web浏览器)。

但是,如果多个应用程序可以响应意图,并且用户可能希望每次都使用其他应用程序,则应明确显示选择器对话框。选择器对话框要求用户每次选择要用于操作的应用程序(用户无法为action选择默认应用程序)。例如,当您的应用使用ACTION_SEND action执行“共享”时,用户可能希望根据其当前情况使用其他应用进行共享,因此您应始终使用选择器对话框,如图2所示。

要显示选择器,请使用createChooser()创建一个Intent并将其传递给startActivity()。例如:

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

// Always use string resources for UI text.
// This says something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// Create intent to show the chooser dialog
Intent chooser = Intent.createChooser(sendIntent, title);

// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

这将显示一个对话框,其中包含响应传递给createChooser()方法的意图的应用程序列表,并使用提供的文本作为对话框标题。

接受隐式意图


要通知系统您的app可以接收哪些隐式意图,请在清单文件中使用<intent-filter>标签为每个应用组件声明一个或多个意图过滤器。每个intent过滤器根据intent的操作,数据和类别指定它接受的意图类型。仅当意图可以通过您的一个意图过滤器时,系统才会向您的应用程序组件提供隐式意图。

注意:无论组件声明什么意图过滤器,显式意图总是会传递给其目标。

应用程序组件应为其可以执行的每个单一操作声明单独的过滤器。例如,图片库应用中的一个activity可能有两个过滤器:一个用于查看图像的过滤器,另一个用于编辑图像的过滤器。当activity启动时,它会检查Intent并根据Intent中的信息决定如何操作(例如是否显示编辑器控件)。

每个意图过滤器在应用程序清单文件中由<intent-filte>标签定义,嵌套在相应的应用程序组件中(<activity>元素)。在<intent-filter>内,您可以使用以下三个元素中的一个或多个来指定要接受的意图类型:

<action>

在name属性中声明接受的intent操作。值必须是操作的文字字符串值,而不是类常量。

<data>

声明接受的数据类型,使用指定数据URI(方案,主机,端口,路径等)和MIME类型的各个方面的一个或多个属性声明。

<category>

在name属性中声明接受的intent类别。值必须是操作的文字字符串值,而不是类常量。

注意:要接收隐式意图,必须在intent过滤器中包含CATEGORY_DEFAULT类别。方法startActivity()和startActivityForResult()将所有意图视为已声明CATEGORY_DEFAULT类别。如果您未在意图过滤器中声明此类别,则不会将隐式意图传达到您的活动。

例如,这是一个带有intent过滤器的活动声明,用于在数据类型为text时接收ACTION_SEND意图:

<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

可以创建一个包含多个<action>,<data>或<category>实例的过滤器。如果这样做,您只需要确定该组件可以处理这些过滤器元素的任何和所有组合。

如果要处理多种意图,但只能处理action,data和category类型的特定组合,则需要创建多个意图过滤器。

通过将意图与三个元素中的每一个进行比较,针对过滤器去比对隐式意图。要传递给组件,意图必须通过所有三个比对。如果它不能匹配其中一个,Android系统将不会将意图传递给组件。但是,由于组件可能具有多个intent过滤器,因此不通过组件某个过滤器的intent可能会在另一个过滤器上通过。有关如何解析意图的更多信息,请参阅以下有关Intent Resolution的部分。

警告:为避免无意中运行其他应用程序的服务,请始终使用显式意图来启动您自己的service,并且不要为您的service声明意图过滤器。

注意:对于所有activity,您必须在清单文件中声明您的intent过滤器。但是对于广播接收器,可以通过调用registerReceiver()动态注册广播接收器的过滤器。然后,您可以使用unregisterReceiver()取消注册接收器。这样做可以让您的应用在应用运行时仅在指定的时间段内收听特定的广播。

过滤器举例

要更好地了解某些意图过滤器行为,请查看社交共享应用程序清单文件中的以下代码段。

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

第一个活动MainActivity是应用程序的主要入口点 - 当用户最初使用启动器图标启动应用程序时打开的活动:

  • ACTION_MAIN操作表明这是主入口点,并且不期望任何意图数据。
  • CATEGORY_LAUNCHER类别表示此活动的图标应放在系统的应用启动器中。如果<activity> 元素未指定icon图标,系统使用<application>元素中的icon作为图标。

这两个必须配对在一起才能使activity出现在应用启动器中。

第二个activity,ShareActivity用于共享文本和媒体内容。用户可以通过从MainActivity导航到此activity,也可以直接从另一个应用程序进入ShareActivity,只需该应用程序发出与两个意图过滤器其中一个匹配的隐式意图。

注意:MIME类型application / vnd.google.panorama360 + jpg是一种特殊数据类型,用于指定全景照片,您可以使用Google全景图API处理这些照片。

使用挂起意图


PendingIntent对象是Intent对象的包装器。 PendingIntent的主要目的是授予外部应用程序使用包含的Intent的权限,就像它是从应用程序自己的进程执行一样。

挂起意图的主要用例包括:

  • 声明当用户使用您的通知执行操作时执行的意图(Android系统的NotificationManager执行Intent)。
  • 声明当用户使用您的App Widget执行操作时执行的意图(主屏幕应用程序执行Intent)。
  • 声明将来在指定时间执行的意图(Android系统的AlarmManager执行Intent)。

因为每个Intent对象由特定类型的app组件(Activity,Service或BroadcastReceiver)处理,所以PendingIntent也必须以相同的考虑因素创建。使用挂起意图时,您的应用程序将不会通过诸如startActivity()之类的调用来执行意图。在通过调用相应的创建者方法创建PendingIntent时,您必须声明预期的组件类型:

  • PendingIntent.getActivity()用于启动Activity的Intent。
  • PendingIntent.getService()用于启动Service的Intent。
  • PendingIntent.getBroadcast()用于启动BroadcastReceiver的Intent。

除非您的app接收另一个app的挂起意图,否则以上是创建挂起意图做常用的方法。

每个方法都传入当前的应用程序Context,要封装的Intent,以及一个或多个指定如何使用intent的标志(例如intent是否可以多次使用)。

有关使用挂起意图的更多信息,请参阅每个相应用例的文档,例如Notifications and App Widgets API指南。

意图解析


当系统收到启动活动的隐式意图时,它会根据以下三个方面通过比较意图与意图过滤器来搜索意图最匹配的activity:

  • The intent action
  • The intent data (both URI and data type)
  • The intent category

以下部分描述了如何根据在应用程序的清单文件中声明的intent过滤器,将Intent与相应的组件进行匹配。

Action比对

为了指定接受的意图action,意图过滤器可以声明零或更多<action>元素。例如:

<intent-filter>
    <action android:name="android.intent.action.EDIT" />
    <action android:name="android.intent.action.VIEW" />
    ...
</intent-filter>

要通过此过滤器,Intent中指定的操作必须与过滤器中列出的操作之一匹配。

如果过滤器未列出任何action,则没有任何意图匹配,因此所有意图都无法通过测试。但是,如果Intent未指定action,则它将通过比对(只要过滤器包含至少一个action)。

Category 比对

为了指定接受的意图类别,意图过滤器可以声明零或更多< category>元素。例如:

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

对于通过类别比对的意图,Intent中的每个类别都必须与过滤器中的类别匹配。反过来不是必需的 - 意图过滤器可以声明比Intent中指定的类别更多的类别,Intent还是可以通过比对。

因此,无论过滤器中声明了哪些类别,没有类别的intent都应该始终通过此比对。

注意:Android会自动将CATEGORY_DEFAULT类别应用于传递给startActivity()和startActivityForResult()的所有隐式意图。因此,如果您希望活动接收隐式意图,则必须在其意图过滤器中包含“android.intent.category.DEFAULT”的类别(如前面的<intent-filter>示例所示)。

Data 比对

为了指定接受的意图数据,意图过滤器可以声明零个或多个<data>元素。例如:

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

每个<data> 元素可以指定URI结构和数据类型(MIME媒体类型)。 URI的每个部分都有单独的属性 - 方案,主机,端口和路径:

<scheme>://<host>:<port>/<path>

例如:

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

在此URI中,方案是content,主机是com.example.project,端口是200,路径是文件夹/子文件夹/ etc。

这些属性中的每一个在< data>中都是可选的。但有依赖关系:

  • 如果未指定方案,则忽略主机。
  • 如果未指定主机,则端忽略端口。
  • 如果方案和主机都为指定,则忽略路径。

当intent中的URI与过滤器中的URI规范进行比较时,它仅与过滤器中包含的URI部分进行比较。例如:

  • 如果过滤器仅指定方案,则具有该方案的所有URI都与过滤器匹配。
  • 如果过滤器指定方案和权限但没有路径,则具有相同方案和权限的所有URI都将通过过滤器,而不管其路径如何。
  • 如果过滤器指定方案,权限和路径,则只有具有相同方案,权限和路径的URI才会通过过滤器。

注意:路径规范可以使用通配符星号(*),只需要路径名的部分匹配。

数据比对将intent中的URI和MIME类型与过滤器中指定的URI和MIME类型进行比较。规则如下:

  1. 仅当过滤器未指定任何URI或MIME类型时,不包含URI或MIME类型的intent才会通过测试。
  2. 包含URI但没有MIME类型的意图(既不显式也不能从URI中提取)只有在其URI与过滤器的URI格式匹配且过滤器同样未指定MIME类型时才会通过测试。
  3. 仅当过滤器列出相同的MIME类型且未指定URI格式时,包含MIME类型但不包含URI的intent才会通过测试。
  4. An intent that contains both a URI and a MIME type (either explicit or inferable from the URI) passes the MIME type part of the test only if that type matches a type listed in the filter. It passes the URI part of the test either if its URI matches a URI in the filter or if it has a content: or file: URI and the filter does not specify a URI. In other words, a component is presumed to support content: and file: data if its filter lists only a MIME type.

最后一条规则(4)反映了组件能够从文件或content provider中获取本地数据的能力。因此,他们的过滤器只需列出数据类型,而不需要明确指定content:和file:的schemes。这里有一个典型案例。以下<data>元素告诉Android该组件可以从内容提供者获取图像数据并显示它:

<intent-filter>
    <data android:mimeType="image/*" />
    ...
</intent-filter>

由于大多数可用数据由内容提供者分发,因此指定数据类型但不指定URI的过滤器可能是最常见的。

另一种常见配置是具有方案和数据类型的过滤器。例如,像下面这样的<data>元素告诉Android该组件可以从网络中检索视频数据以执行操作:

<intent-filter>
    <data android:scheme="http" android:type="video/*" />
    ...
</intent-filter>

意图匹配

Intent与intent过滤器匹配,不仅可以发现要激活的目标组件,还可以发现有关设备上组件集的信息。例如,Home应用程序通过使用指定ACTION_MAIN操作和CATEGORY_LAUNCHER类别的intent过滤器查找所有活动来填充应用程序启动器。

您的应用程序可以以类似的方式使用意图匹配。PackageManager有一组查询...()方法,它们返回所有可以接受特定意图的组件,以及一系列类似的resolve ...()方法,用于确定响应意图的最佳组件。例如,queryIntentActivities()返回可以执行作为参数传递的intent的所有活动的列表,queryIntentServices()返回类似的服务列表。这两种方法都没有激活组件;他们只列出可以响应的那些组件。对于广播接收器,有一种类似的方法queryBroadcastReceivers()。

猜你喜欢

转载自blog.csdn.net/weixin_42703445/article/details/82885138