Intent 和Intent Filter

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 Android应用程序中三个主要的组件——Activity, Service, Broadcast receiver——都是由Intent中传递过来的消息激活的,

Intent
消息传递是这样一个工具,它把相同或者不同应用的组件后期运行绑定起来。
Intent对象本身是一个被动的数据结构,它用来承载一个抽象描述,这个抽象描述是关于将要执行操作基本属性。—— broadcast的情况下,这个描述是已经发生,并且正在被announced的东西[这句要继续深刻理解一下]。下面有很多相互独立机制,为每种类型的组件传递Intent:
1.
一个Intent 对象传给Context.startActivity()或者Activity.startActivityForResult() 去启动一个Activity或者利用已存在的Activity执行某项操作
.
2.一个Intent 对象传给Content.startService(),初始化一个Service或者为一个正在进行的Service传递新的指示。同样地,一个intent对象传给Context.bindService(),用来建立主动调用的组件和目标Service之间的连接。如果Service尚未运行,则可选择性的启动。

3.Intent
对象传递给任意broadcast方法,Context.sendBroadcast(), Context.sendOrderBroadCast(),或者 Context.sendStickyBroadCast(),这种方式的传递,会将Intent传递给所有感兴趣的Broadcastreceiver. 许多broadcast起源于系统代码。
在上述各情况下,Android系统要找到需要的Activity, Service, 或者是broadcast receiver的集合,从而响应intent消息,并且在需要的情况下初始化这些组件。这些Intent消息没有交集broadcast intent只送往broadcast receiver, 不会送往activity或者service. 一个Intent传给startActivity(), 只会送往activity, 不会送给一个service或者broadcast receiver
本文档开篇介绍Intent对象. 然后介绍Androidintent和组件的映射规则——Android如何解决那个组件应该接收一个Intent消息。由于Intent没有明显的指明要调用哪个Component, 这个过程包含测试Intent对象和关联潜在目标组件的Intent filter.

 Intent Objects:
一个Intent对象是信息的集合. 它包含需要接收这个Intent的组件感兴趣的消息(如产生什么样的动作,以及这个动作的数据对象),还包含Android系统需要的附加信息(需要处理这个Intent的组件分类,以及如何启动目标Activity), 原则上,一个Intent包含如下信息:
Component Name:
处理这个Intent的组件名称。 这是一个ComponentName属性对象——目标组件的类全名(如"com.example.project.app.FreneticActivity")以及在manifest文件中,设置组件Package位置的信息("com.example.project"). 组件名称的package部分和package的名称不一定要完全匹配。
组件名称是可选的, 如果设置了这个组件名称, Intent对象会发送到指定组件的实例。如果没有设置,Android利用其它的信息定位和是的组件目标——查看后续章节的 Intent Resolution.
组件的名称通过setComponent(), setClass(), setClassName()设置,通过getComponent读取。

Action:它是将要执行动作的字符串名称——对于Broadcast Intent, 发生的Action不断上报。 Intent类定义了许多Action 常量,包括下面的:

这里是一个表格.后面去移植
.

可以查看API,可以发现预先定义的一些Action常量. 其它的一些Actions定义在Android api的其他地方,可以在自己的应用中,自定义可以被组件激活的Action字符串。这些自定义的需要将应用程序的包名作为前缀,如
"com.example.project.SHOW_COLOR".

Action
很大程度上决定了Intent的其他部分的组织结构——特别是Intentdataextras属性——如同一个方法名决定了传入的参数和返回值。
鉴于上述原因,明智的做法是:尽可能的使用特别的Action名称,并且和Intent的其他属性紧紧绑定。换句话说,为你的组件用到的Intent对象定义一个完整的约定,而不是每个Action无规则的各自定义。
IntentAction的设置是用setAction(),读取采用getAction();

 

Data:指的是操作的数据以及这个数据的MIME类型。不同的Action对应不同的数据说明。 比如,如果Intent的的action属性为

ACTION_EDIT,
则为了显示并编辑,Intentdata属性需要包含文档的URI; 如果Intentation属性为ACTION_CALL, Intentdata

性需要为tel:包含拨打电话的URI. 同样地,如果Intentaction域为ACTION_VIEW并且Intentdata域为http:URI, 接收Intent

Activity
将被调用并且下载和现实这个URI表示的资源。
当匹配一个Intent到一个组件,并且能够处理数据时,除了了解URI外,获知这个数据的MIME类型是很重要的。比如,一个能打开图

像文件的组件,不应该用来播放音频文件。
在很多情况下,可以从URI推断出data的类型——特别是content:URIs,它表示数据位于设备中,并且有一个content provider控制(查看

separate discussion on consten providers).
但是,数据类型同样可以显示的在Intent对象找哦你个设置. setData()方法仅仅设置

数据的URI setType()方法仅仅设置数据的MIMIE类型,setDataAndType()同时设定URIMIME类型。通过getData()URI,通过

getType()
MIME类型

Category:指的是一个包含附加信息的String,附加信息是关于应该处理Intent的组件类型。任意数目的category描述都可以防止到一

Intent 对象中. Action的做法类似,intent类也定义了多个catagory常量,如:
这是一个表....稍后去迁移.
API文档中的Intent, 可以获得所有Category列表
.
addCategory()
方法将一个Category设置到Intent对象中。removeCategory() 删除一个之前设置的Category. getCategoryies()方法得


到当前Intent对象中所有的categories.

Extras:
指的是一个Key-Value对,用来给目标组件传递附加信息,正如某些Action和特定的数据URI一样的对应关系,存在某些特殊


extras, 比如: 一个ACTION_TIMEZONE_CHANGED intent有一个"time-zone" extra定义了一个新时区,ACTION_HEADSET_PLUG 有一

"state" extra 表明耳机是否插上还是拔出,而"name" extra则表明了耳机的类型. 如果你需要实现一个SHOW_COLOR action, color

的值需要在extrakey-value对中被设置好。

Intent
对象中有一系列的putXXX()方法,可以插入不同种类的extra 数据,同样有一系列getXXX()方法用来读取数据. 这些方法对

Bundle
对象而言都是平行的. 事实上,这些extras可以用Bundle的形式,通过putExtras()getExtras()方法插入和存取。
Flags:
指的是各种各样的标志。大多数用来告知Android系统如何启动一个Activity(Activity属于哪个task),如何在启动之后处理

这个Activity(Activity是否在最近的Activities集合中). 所有的这些标志都定义在Intent类中。

所有总结:
Android
系统和它所带的应用程序利用Intent对象, 发送系统产生的broadcast并且激活系统定义的component. 想谅解如何结构化一个Intent对象,并激活系统组件,参考:list of intents.

1. IntentActivity关联关系
  
通过传递的Intent来决定Activity的启动。IntentActivity的关系是一对多,比如,传递一个Typemp3Intent,可能会让你选

择多个Activity——Android自带的音乐播放或者你自己选择的播放器等。ActivityAndroidManifest.xml中预先定义了与哪个Intent相关,这样方便后面传递Intent,即可以激活对应的Activity

2. Intent
Activity的全局性.
  
无疑可以自定义ActivityIntent-Filter,这样每个应用(可以称为进程吗?)自己搞定自己的事情就OK 但为了应用之间通信


的方便, 比如,系统已经有了一个音乐播放器Activity,何必自己再实现? 因此只需要构造能让该播放器Activity识别的Intent

行了。 因此通过一些全局的变量塑造Intent,就实现了Activity的复用。方式是利用Intent中的全局常量,如

Intent.ACTION_MAIN,Intent.CATEGORY_SAMPLE_CODE
等,定义到Acitity中,这样大家都能使用这样的Activity了。

简单示例:
    private void testPM()
    {
    Intent mainIntent = new Intent("com.ostrichmyself.xxx", null);
    PackageManager pm = getPackageManager();
         List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);
         for (int i = 0; i < list.size(); i++)
         {
        ResolveInfo info = list.get(i);
        Log.i("Test Intent---", info.activityInfo.name);
         }
        
    }

   AndroidManifest.xml
中定义为:
    <activity android:name=".MyActivity" android:label="myActivity">
      <intent-filter>
           <action android:name="com.ostrichmyself.xxx" />
      </intent-filter>
    </activity>

注意TestPM()这段代码可以放在和MyActivity所在的application中,也可以放在其它地方。 原因是Activity是全局的。

androidApplication Components四个部分组成:

 

  1 Activities

  2  Services

  3 Broadcast receivers

  4 Content provider

Activities

 

      一个activity是一个可视化的用户界面,可以上面添加layout view button等。一个android由多个activity组成,各个activity之间相互独立。每一个activity实现都是Activity这个基类的子类。

 

Services

 

     service程序没有用户界面,但是可以长时间在后台运行,比如可以音乐的后台播放功能。   

 

Broadcast receivers

 

     Broadcast receivers 是一个用来接收响应外部事件消息(broadcast announcements 我翻译不好)的组件。Broadcast receivers没有用户界面,用户看不到它,但是它可以通过一个activity、震动、响铃、状态栏等提示用户有外部消息。所有的事件接收响应继承自BroadcastReceiver基类。

 

Content provider

 

     Content provider提供一组标准的方法接口,供其他应用程序调用。例如,应用程序A通过实现ContentProvider的接口将自己数据暴露出去,外部应用程序可以通过ContentProvider接口对A的数据进行操作(增删改查等)。

 

      android中数据是私有的不公开的(文件存储数据、SQLite数据库数据库、或者其他数据),通过Content provider可以将私有数据暴露出去。

 Intent Intent Filter(参考android入门开发与实践一书)

      一个Intent就是一次就将要执行操作的抽象描述(抽象啊)。Intent最重要的两个部分是ActionIntent的动作)和DataAction对应的数据)。Action的类型有MAINActivity的门户)、VIEWEDIT等等,Action对应的DataURI形式描述。例如要查看某人联系方式,需要创建一个Action类型为viewIntent,以及一个表示此人的URIIntent也可以进行Activity之间的跳转。

 

   

     Intent Filter用于描述一个Activity(或Intent Receiver)能操作哪些Intent。例如一个Activity要显示某人联系方式,需要声明一个Intent FilterIntent Filter需要知道怎么处理view动作和表示某人的URIIntent Filter一般在AndroidManifest.xml中定义。           Intent  in = new Intent(A.class, B.class);  startActivity(in);

   

意图解析Intent Resolution

 

意图可以被分成两组:

 

显式意图  通过名字指明目标组件(这个组件名字字段component name field, 前面提到过, 有一个数值集)。既然组件名称通常不为其他应用程序的开发者所了解,显式意图典型的被用作应用程序的内部消息

-例如一个活动启动一个附属服务或姊妹活动。

隐式意图  不命名目标组件(组件名称字段为空)。隐式意图经常用来激活其他应用程序的组件。

Android递交一个显式的意图给一个指定目标类的实例。意图对象中的组件名称唯一的确定哪个组件应该获取这个意图。隐式意图需要一个不同的策略。在没有指定目标的情况下,Android系统必须找到最合适的组件来处理这个意图-单个活动或者服务来执行这个请求动作或者一系列的广播接收器来应对广播通告。

 

这是通过比较意图对象的内容和意图过滤器,有可能接收意图的组件相关结构。过滤器公布一个组件具备的能力以及限定它能处理的意图。他们使组件接收该公布类型的隐式意图成为可能。如果一个组件没有任何的意图过滤器,那它只能接收显式意图。一个带过滤器的组件可以同时接收显式和隐式意图。

 

当一个意图对象被一个意图过滤器测试时,只有三个方面会被参考到:

 

动作

数据(URI以及数据类型)

类别

 

附加信息和标志并不参与解析哪个组件接收一个意图。

 

 

 

意图过滤器Intent filters

 

为了通知系统它们可以处理哪些意图,活动、服务和广播接收器可以有一个或多个意图过滤器。每个过滤器描述组件的一个能力,一系列组件想要接收的意图。它实际上按照一个期望的类型来进行意图滤入,同时滤出不想要的意图-但是只有不想要的隐式意图会被滤出(那些没有命名目标的对象类)。一个显式意图总能够被递交给它的目标,而无论它包含什么。这种情况下过滤器不起作用。但是一个显式意图仅当它能通过组件的一个过滤器时才可以被递交到这个组件。

 

组件为它能做的每项工作,每个呈现给用户的不同方面分有不同的过滤器。比如,范例记事本应用程序中的主要活动有三个过滤器-一个是空白板,另一个是用户可以查看、编辑、或选择的一个指定的记事目录,第三是在没有初始目录说明的情况下查找一个特定的记录。一个意图过滤器是IntentFilter类的一个实例。但是,由于Android系统在启动一个组件前必须知道这个组件的能力,意图过滤器通常不会用Java代码来设置,而是在应用程序清单文件(AndroidManifest.xml)中设置<intent-filter>元素。(有一个例外,通过调用Context.registerReceiver() 来注册的广播接收器的过滤器;它们是作为意图过滤器对象而被直接创建的。

 

 

 

过滤器与安全Filters and security

 

不能信赖一个意图过滤器的安全性。当它打开一个组件来接收某些特定类型的隐式意图,它并不能阻止以这个组件为目标的显式意图。即使过滤器对组件要处理的意图限制某些动作和数据源,总有人能把一个显式意图和一个不同的动作及数据源组合在一起,然后命名该组件为目标。

 

一个过滤器和意图对象有同样的动作、数据以及类别字段。一个隐式意图在过滤器的所有三个方面都被测试。为了递交到拥有这个过滤器的组件,它必须通过所有这三项测试。即便只有一个不通过,Android系统都不会把它递交给这个组件-至少以那个过滤器的标准而言。不过,由于一个组件可以包含多个意图过滤器,一个不能通过其中一个组件过滤器的意图可能在另外的过滤器上获得通过。

 

三个测试详细描述如下:

 

动作测试Action test

 

清单文件中的意图过滤器元素里列举了动作元素,比如:

 

<intent-filter . . . >

 

     <action android:name="com.example.project.SHOW_CURRENT" />

 

     <action android:name="com.example.project.SHOW_RECENT" />

 

     <action android:name="com.example.project.SHOW_PENDING" />

 

     . . .

 

 </intent-filter>

 

如同例子所示,一个意图对象只对单个动作命名,而一个过滤器可能列举多个。列表不能为空;一个过滤器必须包含至少一个动作元素,否则它将阻塞所有的意图。

 

为了通过这个测试,在意图对象中指定的动作必须匹配过滤器中所列举的动作之一。如果意图对象或过滤器不指定一个动作,结果将如下:

 

·         如果这个过滤器没有列出任何动作,那意图就没有什么可匹配的,因此所有的意图都会测试失败。没有意图能够通过这个过滤器。

 

·         另一方面,一个未指定动作的意图对象自动通过这个测试-只要过滤器包含至少一个动作。

 

类别测试Category test

 

一个意图过滤器<intent-filter>元素也列举了类别作为子元素。比如:

 

<intent-filter . . . >

 

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

 

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

 

     . . .

 

</intent-filter>

 

注意前面描述的动作和类别常量没有在清单文件中使用。相反使用了完整的字符串。比如,对应于前述CATEGORY_BROWSABLE常量,上面的例子里使用了"android.intent.category.BROWSABLE"字符串。类似的,字符串"android.intent.action.EDIT" 对应于ACTION_EDIT常量。

 

对一个通过类别测试的意图,每个意图对象中的类别必须匹配一个过滤器中的类别。这个过滤器可以列举另外的类别,但它不能遗漏任何在这个意图中的类别。

 

因此,原则上一个没有类别的意图对象应该总能够通过测试,而不管过滤器里有什么。绝大部分情况下这个是对的。但有一个例外,Android把所有传给startActivity()的隐式意图当作他们包含至少一个类别:"android.intent.category.DEFAULT" CATEGORY_DEFAULT常量)。 因此,想要接收隐式意图的活动必须在它们的意图过滤器中包含"android.intent.category.DEFAULT"。(带"android.intent.action.MAIN""android.intent.category.LAUNCHER"设置的过滤器是例外)。它们标记那些启动新任务和呈现在启动屏幕的活动。它们可以在类别列表中包含"android.intent.category.DEFAULT",但不是必要的。) 可查阅后面的使用意图匹配(Using intent matching)以获得更多关于过滤器的信息。

 

数据测试Data test

 

就像动作和类别,一个意图过滤器的数据规格被包含在一个子元素中。而且这个子元素可以出现多次或一次都不出现。例如:

 

<intent-filter . . . >

 

     <data android:type="video/mpeg" android:scheme="http" . . . />

 

     <data android:type="audio/mpeg" android:scheme="http" . . . />

 

     . . .

 

 </intent-filter>

 

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

 

scheme://host:port/path

 

比如,在下面的URI里面,

 

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

 

模式是"内容",主机是"com.example.project",端口是"200",路经是"folder/subfolder/etc"。主机和端口一起组成URI鉴权(authority);如果未指定主机,端口会被忽略。

 

这些属性都是可选的,但彼此有依赖关系:一个授权要有意义,必须指定一个模式。一个路经要有意义,必须同时指定模式和鉴权。

 

当一个意图对象中的URI被用来和一个过滤器中的URI规格比较时,它实际上比较的是上面提到的URI的各个部分。比如,如果过滤器仅指定了一个模式,所有那个模式的URIs和这个过滤器相匹配;如果过滤器指定了一个模式、鉴权但没有路经,所有相同模式和鉴权的URIs可以匹配上,而不管它们的路经;如果过滤器指定了一个模式、鉴权和路经,只有相同模式、鉴权和路经的URIs可以匹配上。当然,一个过滤器中的路径规格可以包含通配符,这样只需要部分匹配即可。

 

数据<data>元素的类型属性指定了数据的MIME类型。这在过滤器里比在URI里更为常见。意图对象和过滤器都可以使用一个"*"通配符指定子类型字段-比如,"text/*"或者"audio/*"-指示任何匹配的子类型。

 

数据测试同时比较意图对象和过滤器中指定的URI和数据类型。规则如下:

 

a.     一个既不包含URI也不包含数据类型的意图对象仅在过滤器也同样没有指定任何URIs和数据类型的情况下才能通过测试。

 

b.    一个包含URI但没有数据类型的意图对象仅在它的URI和一个同样没有指定数据类型的过滤器里的URI匹配时才能通过测试。这通常发生在类似于mailto:tel:这样的URIs上:它们并不引用实际数据。

 

c.     一个包含数据类型但不包含URI的意图对象仅在这个过滤器列举了同样的数据类型而且也没有指定一个URI的情况下才能通过测试。

 

d.    一个同时包含URI和数据类型(或者可从URI推断出数据类型)的意图对象可以通过测试,如果它的类型和过滤器中列举的类型相匹配的话。如果它的URI和这个过滤器中的一个URI相匹配或者它有一个内容content:或者文件file: URI而且这个过滤器没有指定一个URI,那么它也能通过测试。换句话说,一个组件被假定为支持content:file: 数据如果它的过滤器仅列举了一个数据类型。

 

如果一个意图可以通过不止一个活动或服务的过滤器,用户可能会被询问要激活那个组件。如果没有发现目标对象将会出现异常。

 

 

 

通常情况Common cases

 

上面描述的数据测试的最后一个规则(d),表达了这样一个期望即组件能够从文件或内容提供者中获取本地数据。因此,它们的过滤器可以只列举一个数据类型而不需要显式的命名content:file:模式。这是一个典型情况。比如,一个如下的数据<data>元素,告诉Android这个组件能从内容提供者获取图片数据并显示:

 

<data android:type="image/*" />

 

既然大多数可用数据是通过内容提供者来分发,那么过滤器最通常的配置就是指定一个数据类型而不指定URI。另外一个通用的配置是带有一个模式和数据类型的过滤器。比如,一个如下的数据<data>元素告诉Android可以从网络获取视频数据并显示:

 

<data android:scheme="http" android:type="video/*" />

 

比如,想一下,当用户点击网页上的一个链接时浏览器做了什么。它首先试图去显示这个数据(如果这个链接指向一个HTML页面)。如果它不能显示这个数据,它会把一个显式意图和一个模式、数据类型组成整体然后尝试启动一个可以处理这个工作的活动。如果没有接受者,它将要求下载管理器来下载数据。这让它处于内容提供者的控制下,以便一个潜在的更大的活动池可以做出反应。

 

大多数应用程序同样有一个方法去启动刷新,而不包含任何特定数据的引用。能初始化应用程序的活动拥有指定动作为"android.intent.action.MAIN"的过滤器。如果它们表述在应用程序启动器中,那它们同样指定了"android.intent.category.LAUNCHER"类别:

 

<intent-filter . . . >

 

     <action android:name="code android.intent.action.MAIN" />

 

     <category android:name="code android.intent.category.LAUNCHER" />

 

 </intent-filter>

 

 

 

使用意图匹配Using intent matching

 

通过意图过滤器匹配的意图不仅是为了发现要激活的目标组件,而且为了发现这个设备上的一系列组件的某些东西。比如,Android系统通过查找符合条件的所有活动(需要包含指定了动作"android.intent.action.MAIN""android.intent.category.LAUNCHER"类别的意图过滤器,如前面章节所述)来产生应用程序启动器,也就是用户可用程序的前置屏幕。然后它显示在这个启动器里的这些活动的图标和标签。类似的,它通过查找其过滤器配有"android.intent.category.HOME"元素的活动来发现桌面。

 

你的应用程序可以用类似的方式使用意图匹配。PackageManager有一系列的查询query…()方法可以接收一个特定的意图,以及相似的一个解析resolve…()方法系列可以确定应答意图的最佳组件。比如,queryIntentActivities()返回一个所有活动的列表,而queryIntentServices()返回一个类似的服务列表。两个方法都不会激活组件;它们仅仅列举能应答的。对于广播接收者,有一个类似的方法queryBroadcastReceivers()

 

 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wong_judy/archive/2010/03/20/5398472.aspx

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值