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

Intent详解

2016-12-30 19:12 162 查看
在说到Activity其它部分内容以及其余的组件之前,有必要了解一下四大组件之间的纽带——intent。

概念

Android中提供了intent机制来协助应用之间的交互和通信,或者采用更准确的说法是,intent不仅可用于应用程序之间,也可用于应用程序内部的activity,service和broadcast receiver之间的交互。intent这个英语单词的本意是意图、意向、目的。



Intent 是一个消息传递对象,您可以使用它从其他应用组件请求操作。尽管 Intent 可以通过多种方式促进组件之间的通信,但其基本用例主要包括以下三个:

·启动 Activity:

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

如果您希望在 Activity 完成后收到结果,请调用 startActivityForResult()。在 Activity 的 onActivityResult() 回调中,您的 Activity 将结果作为单独的 Intent 对象接收。
·启动服务:

Service 是一个不使用用户界面而在后台执行操作的组件。通过将 Intent 传递给 startService(),您可以启动服务执行一次性操作(例如,下载文件)。Intent 描述了要启动的服务,并携带了任何必要的数据。

如果服务旨在使用客户端-服务器接口,则通过将 Intent 传递给 bindService(),您可以从其他组件绑定到此服务。
·传递广播:

广播是任何应用均可接收的消息。系统将针对系统事件(例如:系统启动或设备开始充电时)传递各种广播。通过将 Intent 传递给 sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast(),您可以将广播传递给其他应用。

Intent 类型

显式 Intent:按名称(完全限定类名)指定要启动的组件。 通常,您会在自己的应用中使用显式 Intent 来启动组件,这是因为您知道要启动的 Activity 或服务的类名。例如,启动新 Activity 以响应用户操作,或者启动服务以在后台下载文件。
隐式 Intent :不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理它。 

Intent的相关属性

intent由以下7大部分组成

1、component(组件):目的组件

2、Action(动作):用来表示意图的行动

3、category(类别):用来表现动作的类别

4、data(数据):表示与动作要操作的数据

5、type(数据类型):对于data范例的描写

6、extras(扩展信息):扩展信息

7、Flags(标志位):期望这个意图的运行模式

Intent的创建方式

显式intent:只要设置了component组件的intent都是显式intent,有以下几种设置方式:
component属性其实是intent内部封装的一个对象:
public ComponentName(Context pkg, Class<?> cls) {
mPackage = pkg.getPackageName();
mClass = cls.getName();
}
(这是componentName 的一个构造方法,内部封装了两个字符串用来接收构造方法传递过来的参数)
ComponentName comp=new ComponentName(MainActivity.this,MainActivity.class);
Intent intent=new Intent();
intent.setComponent(comp);


这三行代码用来创建componentName对象,事实上一般不会这么写,我们一般采用这种方式来写:


Intent intent1=new Intent(this,MainActivity.class);
实际上intent内部有一个简化的构造器,方便我们直接指定启动其它组件:
public Intent(Context packageContext, Class<?> cls) {
mComponent = new ComponentName(packageContext, cls);
}
也可以通过下面这种方法来创建显式intent:
Intent intent2 = new Intent();
intent2.setClass(this,MainActivity.class);
不过这种方式也很鸡肋,用的最多的还是直接通过intent的构造函数就行指定要启动的组件
隐式intent:
隐式 Intent 指定能够在可以执行相应操作的设备上调用任何应用的操作。 如果您的应用无法执行该操作而其他应用可以,且您希望用户选取要使用的应用,则使用隐式 Intent 非常有用。一般通过setAction,setCategory等其它属性来进行设置启动

意图过滤器

这个我们看一下清单文件中的意图过滤器:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
第一个 Activity MainActivity 是应用的主要入口点。当用户最初使用启动器图标启动应用时,该 Activity 将打开:
ACTION_MAIN 操作指示这是主要入口点,且不要求输入任何 Intent 数据。
CATEGORY_LAUNCHER 类别指示此 Activity 的图标应放入系统的应用启动器。 如果 <activity> 元素未使用 icon 指定图标,则系统将使用 <application> 元素中的图标。

这两个元素必须配对使用,Activity 才会显示在应用启动器中。
Action表示动作测试:
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
...
</intent-filter>
如果该过滤器未列出任何操作,则 Intent 没有任何匹配项,因此所有 Intent 均无法通过测试。 但是,如果 Intent 未指定操作,则会通过测试(只要过滤器至少包含一个操作)。只要是我们声明的intent中的action是过滤器中action的子集即可。
Category要指定接受的 Intent 类别, Intent 过滤器既可以不声明任何 <category> 元素,也可以声明多个此类元素。 例如:
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
...
</intent-filter>
只要intent中配置的category是该清单文件中的子集即可
注:Android 会自动将 CATEGORY_DEFAULT 类别应用于传递给 startActivity() 和 startActivityForResult() 的所有隐式 Intent。因此,如需 Activity 接收隐式 Intent,则必须将 "android.intent.category.DEFAULT" 的类别包括在其 Intent 过滤器中(如上文的 <intent-filter> 示例所示)。

Data测试:
要指定接受的 Intent 数据, Intent 过滤器既可以不声明任何 <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 属性:

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

例如:

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

在此 URI 中,架构是 content,主机是 com.example.project,端口是 200,路径是 folder/subfolder/etc。

在 <data> 元素中,上述每个属性均为可选,但存在线性依赖关系:

如果未指定架构,则会忽略主机。

如果未指定主机,则会忽略端口。

如果未指定架构和主机,则会忽略路径。

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

如果过滤器仅指定架构,则具有该架构的所有 URI 均与该过滤器匹配。

如果过滤器指定架构和权限,但未指定路径,则具有相同架构和权限的所有 URI 都会通过过滤器,无论其路径如何均是如此。

如果过滤器指定架构、权限和路径,则仅具有相同架构、权限和路径的 URI 才会通过过滤器。

注:路径规范可以包含星号通配符 (*),因此仅需部分匹配路径名即可。

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

仅当过滤器未指定任何 URI 或 MIME 类型时,不含 URI 和 MIME 类型的 Intent 才会通过测试。

对于包含 URI 但不含 MIME 类型(既未显式声明,也无法通过 URI 推断得出)的 Intent,仅当其 URI 与过滤器的 URI 格式匹配、且过滤器同样未指定 MIME 类型时,才会通过测试。

仅当过滤器列出相同的 MIME 类型且未指定 URI 格式时,包含 MIME 类型、但不含 URI 的 Intent 才会通过测试。

仅当 MIME 类型与过滤器中列出的类型匹配时,同时包含 URI 类型和 MIME 类型(通过显式声明,或可以通过 URI 推断得出)的 Intent 才会通过测试的 MIME 类型部分。 如果 Intent 的 URI 与过滤器中的 URI 匹配,或者如果 Intent 具有 content: 或 file: URI 且过滤器未指定 URI,则 Intent 会通过测试的 URI 部分。 换言之,如果过滤器只是列出 MIME 类型,则假定组件支持 content: 和 file: 数据

使用pendingIntent

PendingIntent 对象是 Intent 对象的包装器。PendingIntent 的主要目的是授权外部应用使用包含的 Intent,就像是它从您应用本身的进程中执行的一样。

pending Intent 的主要用例包括:

声明用户使用您的通知执行操作时所要执行的 Intent(Android 系统的 NotificationManager 执行 Intent)。

声明用户使用您的 应用小部件执行操作时要执行的 Intent(主屏幕应用执行 Intent)。

声明未来某一特定时间要执行的 Intent(Android 系统的 AlarmManager 执行 Intent)。

由于每个 Intent 对象均设计为由特定类型的应用组件(Activity、Service 或 BroadcastReceiver)进行处理,因此还必须基于相同的考虑因素创建 PendingIntent。使用pendingIntent 时,应用不会使用调用(如 startActivity())执行该 Intent。相反,通过调用相应的创建器方法创建 PendingIntent 时,您必须声明所需的组件类型:

PendingIntent.getActivity(),适用于启动 Activity 的 Intent。

PendingIntent.getService(),适用于启动 Service 的 Intent。

PendingIntent.getBroadcast(),适用于启动 BroadcastReceiver 的 Intent。

除非您的应用正在从其他应用中接收待定 Intent,否则上述用于创建 PendingIntent 的方法可能是您所需的唯一 PendingIntent 方法。

每种方法均会提取当前的应用 Context、您要包装的 Intent 以及一个或多个指定应如何使用该 Intent 的标志(例如,是否可以多次使用该 Intent)。

使用Intent进行传值

可以先将数据包bundle进行new出来,再通过各种put方法,将数据存进去,再调用intent的putExtras将bundle数据传进去
Intent intent1 = new Intent(this, Main
a4f4
Activity.class);
Bundle bundle=new Bundle();
bundle.putString("data","data");
intent1.putExtra("bundle",bundle);
(个人感觉也很鸡肋,因为intent的putExtra方法是智能的,若没有bundle,它会帮我们创建一个bundle进行装数据)

public Intent putExtra(String name, byte value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putByte(name, value);
return this;
}
因此,我们可以调用各种put方法进行传递数据即可:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息