简介

  1. Intent本意为目的、意向、意图。在Android中,简言之,Intent是系统各组件(或应用程序)之间进行数据传递的数据负载者,Intent不仅可以用于应用程序之间的交互,也可以用于应用程序内部的activity、service和broadcast receiver之间的交互。
  2. 实际上,Intent是一种运行时绑定(run-time binding)机制,它能在程序运行过程中连接两个不同的组件。通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件来完成请求。Intent对象是一个被动的数据结构保存一个将要执行的操作的抽象描述,或在广播的情况下,通常是某事已经发生且正在宣告。Android的三个基本组件——Activity,Service和Broadcast Receiver都是通过Intent机制激活的,不同类型的组件有不同的传递Intent机制:

    1. 启动Activity

      1. 使用Context.startActivity()或Activity.startActivityForRestult()去启动一个Activity或使一个已存在的Activity去做新的事情。
      2. 使用Activity.setRestult()传入一intent来从activity中返回结果。

      具体详见1。

    2. 启动Service

      1. 使用Context.startService()去初始化一个service或传递消息给正在运行的service。
      2. 使用Context.bindService()去建立调用组件和目标服务之间的连接(即绑定service)。

      具体详见2。

    3. 启动broadcast receiver
      将intent对象传递给任何广播方法(如Context.sendBroadcast(),Context.sendOrderedBroadcast(),Context.sendStickyBroadcast()),都将传递到所有感兴趣的广播接收者。

    目前还没实现这部分,具体详见,,。
    只有广播不能绑定服务,能通启动。

在讲解Intent属性之前必须先了解一下系统如何通过Intent找到用户所希望的组件。这就要涉及到Intent Filter匹配。下面以在Activity中设置为例。

Intent Filter

Intent Filter 描述了一个组件愿意接收什么样的 Intent 对象,Android 将其抽象为 android.content.IntentFilter 类。在 Android 的 AndroidManifest.xml 配置文件中的<activity>标签中可以通过< intent-filter> 标签为一个 Activity 指定其 Intent Filter,以便告诉系统该 Activity 可以响应什么类型的 Intent对象。

当程序员使用 startActivity() 或startActivityForRestult()来启动另外一个 Activity 时,如果直接指定 了Intent 对象的 Component 属性(多种方式,下面有详细介绍),那么 Activity Manager 将试图启动其 Component 属性指定的 Activity。否则 Android 将通过 Intent 的其它属性从安装在系统中的所有 Activity 中查找与之最匹配的一个启动(或当优先级相同时通过列表让用户自己选择),如果没有找到合适的 Activity,应用程序会得到一个系统抛出的异常。这个匹配的过程如下3:

注:

  • URI数据即为属性data,此处意思表示必须匹配data或type,若同时出现则必须两者都匹配。
  • 三种检测(动作检测(Action),种类检测(Category),数据检测(包括data和type))

Intent的解析

Intent分类

在应用中,我们可以以两种形式来使用Intent:

  • 显式Intent,即指定组件形式
    指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context, Class)来指定)或者直接用构造器Intent(Context,Class)。通过指定具体的组件类,通知应用启动对应的组件。
  • 隐式Intent,即通过Intent Filter过滤匹配
    没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在所有的可用组件中,确定满足此Intent的组件。

对于显式Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些隐式Intent,通过解析将 Intent对象映射给可以处理此Intent的Activity、Service或Broadcast Receiver对象。

Intent解析机制

前面已经提到Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有<intent-filter>及其中定义的Intent,通过PackageManager(注:PackageManager能够得到当前设备上所安装的
application package的信息,可以参见4)来查找能处理这个Intent的component。在这个解析过程中,Android是通过Intent的action、type或data、category这三个属性来进行判断的,判断方法如下:

  1. 如果Intent指明了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配;
  2. 如果Intent没有提供type,系统将从data中得到数据类型。和action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。
  3. 如果Intent中的数据不是content类型的URi,而且Intent也没有明确指定type,将根据Intent中数据的scheme(比如 http或者tel)进行匹配。同上,Intent 的scheme必须出现在目标组件的scheme列表中。
  4. 如果Intent指定了一个或多个category,这些类别必须全部出现在组件的类别列表中。

目前先了解如何匹配过程,后面应看如何实现的,即看源码可以参考5。

Intent属性

Intent由以下各个组成部分:

  • component
    目的组件
  • action
    表示意图的行动
  • catecory
    表示动作的类别
  • data
    表示动作要操作的数据
  • type
    data的数据类型描述
  • extras
    扩展信息
  • flags
    设置组件的启动模式

下面具体介绍各个属性(以启动Activity为例)

组件Component

指定Intent对象的目标组件的类名称。指定component的话,将直接使用并启动它指定的组件,Intent的其它所有属性都是可选的。此为显式Intent,即直接启动指定的组件。

组件名字是可选的,如果设置了,intent对象传递到指定类的实例;如果没有设置,Android使用intent中的其它属性来定位合适的目标组件。组件的名字通过setComponent(),setClass()或setClassName()设置均可,通过getComponent()读取。其中,setComponent()接收一个ComponentName类实例,ComponentName构造器代码如下:

三种ComponentName构造器(源码)

/** * Create a new component identifier. * * @param pkg The name of the package that the component exists in. Can * not be null. * @param cls The name of the class inside of <var>pkg</var> that * implements the component. Can not be null. */    public ComponentName(String pkg, String cls) {        if (pkg == null) throw new NullPointerException("package name is null");        if (cls == null) throw new NullPointerException("class name is null");        mPackage = pkg;        mClass = cls;    }    /** * Create a new component identifier from a Context and class name. * * @param pkg A Context for the package implementing the component, * from which the actual package name will be retrieved. * @param cls The name of the class inside of <var>pkg</var> that * implements the component. */    public ComponentName(Context pkg, String cls) {        if (cls == null) throw new NullPointerException("class name is null");        mPackage = pkg.getPackageName();        mClass = cls;    }    /** * Create a new component identifier from a Context and Class object. * * @param pkg A Context for the package implementing the component, from * which the actual package name will be retrieved. * @param cls The Class object of the desired component, from which the * actual class name will be retrieved. */    public ComponentName(Context pkg, Class<?> cls) {        mPackage = pkg.getPackageName();        mClass = cls.getName();    }

其实,这三种构造器本质都一样。

显示Intent启动另一个Activity

代码如下:

/** * 使用component属性设置Intent对象,启动一个Activity * */Intent intent = new Intent();//构造器有多种,也可以为new ComponentName(this,MainActivity2.class);//同样也有启动其它包中activity的构造器ComponentName componentName = new ComponentName(this,"com.sywyg.intent_test.MainActivity2");intent.setComponent(componentName);startActivity(intent);

需要注意的是,如果我们在Intent中指定了component属性,系统将不会再对action、data/type、category进行匹配。

动作action

表示意图的动作。例如日常生活中在描述一个意愿时经常带有某种动作,比如我想看爱情动作片,这里看就是一个动作。在Intent中,action就是描述意图的动作。当指明一个action时,目标组件就会依照这个动作的指示,表现对应的行为。Action是一个的字符串,也可以由用户自定义,在Intent中,定义了很多动作,如ACTION_VIEW等基本上涵盖了常用的动作。一个 Intent Filter 可以包含多个 Action。

在 AndroidManifest.xml 的 <activity> 标签中添加在< intent-filter>标签中指定一个 Action 列表用于说明 Activity 所能接受的“动作”,代码如下:

<activity  android:name=".MainActivity2" android:label="@string/title_activity_main_activity2" >    <intent-filter>          <action android:name="com.sywyg.intent_test.MY_ACTION"/>          <category android:name="android.intent.category.DEFAULT"/>    </intent-filter></activity>

注:

  • “com.sywyg.intent_test.MY_ACTION”为自定义字符串,这里为了方便介绍,直接使用字符串。一般使用枚举类实现。
  • 每个Intent只能设置一个动作,而intent-filter中可以添加多个。
  • 若当前组件是Activity,则必须包含一个默认的类别,也有列外(下面有介绍)。

对应的activity中的代码如下:

 /** * 使用action属性设置Intent对象,启动匹配成功的Activity */ Intent intent = new Intent(); intent.setAction("com.sywyg.intent_test.MY_ACTION"); //或直接使用构造器Intent("com.sywyg.intent_test.MY_ACTION")设置动作 startActivity(intent);

所有 Action 列表中包含了”com.sywyg.intent_test.MY_ACTION”的 Activity 都将会匹配成功。如果就一个匹配的Activity则直接跳转到该Activity,如果有多个匹配的Activity,则按优先级排序,返回优先级最高的Activity。若优先级相同,则系统会通过对话框的方式让用户选择。

Android 预定义了一系列的 Action 分别表示特定的系统动作。这些 Action 通过常量的方式定义在 android.content. Intent中以“ACTION_”开头(枚举类实现的),可以在 Android 提供的文档中找到它们的详细说明。当然可以定义自己的动作字符串应在我们的应用程序中激活组件。自定义动作字符串通常应该包含应用程序包名前缀,如”com.sywyg.intent_test.MY_ACTION”。

动作很大程度上决定了剩下的intent如何构建,特别是数据(data和type)和类型(category)字段,就像一个方法名决定了参数和返回值。正是这个原因,应该尽可能明确指定动作,并紧密关联到其它Intent属性。换句话说,应该定义你的组件能够处理的Intent对象的整个协议,而不仅仅是单独地定义一个动作。

类别category

category用于表现动作的类别,相当于把动作分类(如增删改(三个动作)一篇论文,这三个动作都属于编辑类别),Intent和Intent Filter中都可以添加多个。

在 AndroidManifest.xml 的 Activity声明时可以在其 intent-filter 标签中为组件定义一个或多个 category 类别列表,当 Intent 中包含所有相同的Category 类别时匹配(除默认类别)才会成功。AndroidManifest.xml 代码如下:

<intent-filter>   <action android:name="com.sywyg.intent_test.MY_ACTION"/>   <category android:name="com.sywyg.intent_test.CATEGORY"/>   <category android:name="android.intent.category.DEFAULT"/></intent-filter>

对应Activity中的代码如下:

 /** * 使用category属性设置Intent对象,removeCategory()删除一个category, getCategories()获取intent所有的category. */ Intent intent = new Intent(); intent.setAction("com.sywyg.intent_test.MY_ACTION"); intent.addCategory("com.sywyg.intent_test.CATEGORY"); startActivity(intent);

注:

  • 必须和动作一块设置,否则报错。
  • 若当前组件是Activity则,必须在intent-filter标签中再增加一个添加默认的类别:
    <category android:name="android.intent.category.DEFAULT"/>PS:多说一句看准IDE自动补全的是不是”android.intent.category.DEFAULT”,提示NO Activity。我在这纠结了半天。
  • 在主Activity中设置”android.intent.action.MAIN” 和”android.intent.category.LAUNCHER”,它们分别标记活动开始新的任务和带到启动列表界面。该Activity可以包含”android.intent.category.DEFAULT”,也可以不包含。
    -action 和category最好用枚举类实现。

数据data

data表示动作要操作的数据,更精确地指定当前活动能够响应什么类型的数据。data属性的声明中要指定访问数据的Uri和MIME类型,在<intent-filter>标签中的<data>中有如下主要属性:

  • android:scheme
    指定数据的协议部分,如http、https、tel…,还可以定义自己的前缀
  • android:host
    用于指定数据的主机名部分,如www.google.com,如果定义为“*”则表示任意主机名
  • android:port
    用于指定数据的端口部分,一般紧随在主机名之后。
  • android:path
    用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。
  • android:mimeType
    用于指定可以处理的数据类型,允许使用通配符(模糊说明,如”audio/*”)的方式指定。

host和port一起构成URI的权限(authority),如果host没有指定,port也被忽略。这四个属性都是可选的,但它们之间并不都是完全独立的。要让authority有意义,scheme必须也要指定。要让path有意义,scheme和authority也都必须要指定。

通过这些属性来对应一个典型的Uri格式scheme://host:port/path,例如http://blog.csdn.net/wangyongge85。

当比较intent对象和过滤器的URI时,仅仅比较过滤器中出现的URI属性。例如,如果一个过滤器仅指定了scheme,所有与此scheme的URIs都匹配过滤器;如果一个过滤器指定了scheme和authority,但没有指定path,所有匹配scheme和authority的URIs都通过检测,而不管它们的path;如果四个属性都指定了,要都匹配才能算是匹配。然而,过滤器中的path可以包含通配符来要求匹配path中的一部分。
不同的动作有不同的数据规格。例如(系统提供的),如果动作字段是ACTION_EDIT,数据字段将包含将显示用于编辑的文档的URI;如果动作是ACTION_CALL,数据字段将是一个tel:URI和将拨打的号码;如果动作是ACTION_VIEW,数据字段是一个http:URI,接收活动将被调用去下载和显示URI指向的数据。

在 AndroidManifest.xml 的 Activity 声明时可以在其intent-filter标签中通过<data>标签添加数据,当 Intent 中包含相同的data时匹配才会成功。代码如下:

 <intent-filter  android:priority="100">    <data android:scheme="http" android:host="blog.csdn.net" android:path = "wangyongge85"/> </intent-filter>

注:

  1. android:priority属性设置优先级(-1000到1000,必须有个负值才生效)
  2. <data>标签一般不需要指定过多的内容,如上只需指定android:scheme属性,就可以响应所有的http协议的Intent了。
  3. 协议一般还有geo表示显示地理位置,tel表示拨打电话
  4. 调用系统自带的应用需设置相应的action和data,见Android系统中标准Intent的使用

对应Activity中的代码如下:

/** * 使用data属性设置Intent对象 */Intent intent = new Intent();               intent.setAction("com.sywyg.intent_test.MY_ACTION");                intent.addCategory("com.sywyg.intent_test.CATEGORY");  Uri data = Uri.parse("http://www.sywyg.com");intent.setData(data);       //拨打电话:intent.setData(Uri.parse("tel:10086"));startActivity(intent);

注:

  • 实际上一个data是用一个Uri对象表示
  • 通常情况下使用action + data属性的组合来描述一个意图:做什么。

数据类型type

指定data属性的数据类型或MIME类型(如text/html,text/xml,image/jpg等),但是通常来说,当Intent不指定data属性是type属性才有效,否则系统data属性值分析数据类型,因此无须指定type。
数据类型(type)是将作用于其上的数据的URI和数据的MIME类型。
在AndroidManifest.xml中声明,在data标签中设置
<data android:mimeType="text/html" />,type属性指定数据的MIME类型。Intent对象和过滤器都可以用”*”通配符匹配子类型字段,例如”text/*”,”audio/*”表示任何子类型。

数据检测既要检测URI,也要检测数据类型。规则如下:

  • 一个Intent对象既不包含URI,也不包含数据类型:仅当过滤器也不指定任何URIs和数据类型时,才不能通过检测;否则都能通过。
  • 一个Intent对象包含URI,但不包含数据类型:仅当过滤器也不指定数据类型,同时它们的URI匹配,才能通过检测。例如,mailto:和tel:类型都不指定实际数据。
  • 一个Intent对象包含数据类型,但不包含URI:仅当过滤也只包含数据类型且与Intent相同,才通过检测。
  • 一个Intent对象既包含URI,也包含数据类型(或数据类型能够从URI推断出):数据类型部分,只有与过滤器中之一匹配才算通过;URI部分,它的URI要出现在过滤器中,或者它有content:或file: URI,又或者过滤器没有指定URI。换句话说,如果它的过滤器仅列出了数据类型,组件假定支持content:和file: 。

当匹配一个intent到一个能够处理数据的组件,通常知道数据的类型(它的MIME类型)和它的URI很重要。例如,一个组件能够显示图像数据,不应该被调用去播放一个音频文件。

在许多情况下,数据类型能够从URi中推测,特别是content:URIs,它表示位于设备上的数据且被内容提供者(content provider)控制。但是类型也能够显示地设置,setData()方法指定数据的URi,setType()指定MIME类型(例如:”audio/mp3”),setDataAndType()指定数据的URI和MIME类型。通过getData()读取URI,getType()读取类型。

 /** * 使用type属性设置Intent对象 */  Intent intent = new Intent();  //通常要设置动作和种类,配合data或type  intent.setType("audio/mp3");  startActivity(intent);

通过setData()方法会把type设置为null,相反通过setType()能把data设置为null,如果同时设置两个使用setDataAndType()方法。

扩展信息extras

附加信息,一般用来携带一些数据信息。通过额外的键值对把数据保存在Intent对象中。

Intent对象有一系列的put…()方法用于插入各种附加数据和一系列的get…()用于读取数据。这些方法与Bundle对象的方法类似,实际上,附加信息可以作为一个Bundle使用putBundleExtras()和getBundleExtras()安装和读取。
已在Activity通信中详解,见6。

标志位flags

期望意图的运行模式。Intent类定义了各种各样的标志,许多指示Android系统如何去启动一个活动(例如,活动应该属于那个任务)和启动之后如何对待它(例如,它是否属于最近的活动列表)。
在这里不多讲,后续将结合Activity的启动模式一块讲解,或请参见郭哥出品的文章。
目前只知道对于Activity来讲这里是设置Activity的启动模式的,包括四种详见(还没发表)。也可在Intent对象中通过setFlags()方法设置。

吴秦http://www.cnblogs.com/skynet/archive/2010/07/20/1781644.html
http://www.oschina.net/question/565065_67909
威哥视频
郭霖第一行

  1. http://blog.csdn.net/wangyongge85/article/details/45167903 ↩
  2. http://blog.csdn.net/wangyongge85/article/details/45395167 ↩
  3. http://www.ibm.com/developerworks/cn/opensource/os-cn-android-actvt/#major2 ↩
  4. http://blog.csdn.net/qinjuning/article/details/6867806 ↩
  5. http://blog.csdn.net/qinjuning/article/details/7384906 ↩
  6. http://blog.csdn.net/wangyongge85/article/details/45167903 ↩

更多相关文章

  1. AndroidManifest.xml文件剖析
  2. 客户端微信分享
  3. Android(安卓)利用addView 动态给Activity添加View组件
  4. 关于Android(安卓)intent的知识
  5. Android中的文件存储数据方式
  6. Android中的基本组件(2)
  7. android Content provider 组件
  8. Android之ContentProvider
  9. 温故而知新Android篇之二

随机推荐

  1. [置顶] EditText属性大全
  2. android控件常用属性区别
  3. Android(安卓)利用BroadcastReceiver实时
  4. Android 中调试手段 打印函数调用栈信息
  5. Android处理ListView的条目长按事件
  6. android jetpack 简单livedata和viewmode
  7. RxJava1的使用介绍
  8. Android 4.0源码放出
  9. Thread
  10. Android给控件添加默认点击效果