Android开发指南-框架主题-意图和意图过滤器

意图和意图过滤器Intents and Intent Filtersandroid

 

一个应用程序的三个核心组件-活动,服务和广播接收器是经过消息即意图(Intents)来激活的。Intent消息传送是相同或不一样应用中组件运行时晚绑定的一种机制。意图自己,一个意图对象,是一个包含被执行操做抽象描述的被动的数据结构-或者,对于广播而言,是某件已经发生并被声明的事情的描述。存在不一样的机制来传送意图到每种组件中:浏览器

一个意图对象是传递给Context.startActivity()或者Activity.startActivityForResult()来启动一个活动或者让一个存在的活动去作某些新的事情。
一个意图对象是传递给Context.startService()来发起一个服务或者递交新的指令给运行中的服务。相似的,一个意图能被传递给Context.bindService() 来在调用组件和一个目标服务之间创建链接。做为一个可选项,它能够发起这个服务若是还没运行的话。
传递给任意广播方法(例如Context.sendBroadcast(),Context.sendOrderedBroadcast(), 或者Context.sendStickyBroadcast())的意图对象被传递给全部感兴趣的广播接收者。许多种广播产生于系统代码。 
在每一个例子里,Android系统找到合适的活动,服务,或者一组广播接收者来回应这个意图,必要时实例化它们。这些消息传送系统没有重叠:广播意图仅被传递给广播接收者,永远不会给活动或者服务。一个传送给startActivity()的意图是只会被传递给一个活动,永远不会给一个服务或广播接收者,如此类推。安全

这篇文档以意图对象的描述开始,而后描述Android映射意图到组件的规则-如何解决哪一个组件应该接收一个意图消息。对于没有显式命名一个目标组件的意图,这个过程包括对照与潜在目标相关联的意图过滤器来测试这个意图对象。服务器

 

意图对象Intent Objects网络

一个意图Intent对象是一堆信息。它包含接收这个意图的组件感兴趣的信息(例如将要采起的动做和操做的数据)再加上Android系统感兴趣的信息(例如应该处理这个意图的组件类别和如何启动一个目标活动的指令):数据结构

组件名称Component nameapp

应该处理这个意图的组件名字. 这个字段是一个ComponentName对象- 一个组合物:目标组件的彻底合格的类名 (好比"com.example.project.app.FreneticActivity") 以及应用程序描述文件中设置的组件所在包的名字(好比, "com.example.project"). 这个组件名字的包部分和描述文件中设置的包名字不必定要匹配。ide

组件名字是可选的。若是被设置了,这个意图对象将被传递到指定的类。若是没有, Android使用另外的意图对象中的信息去定位一个合适的目标- 请看本文稍后描述的意图解析Intent Resolution。测试

组件名字经过以下方法:setComponent(),setClass(), 或者setClassName()设置并经过getComponent()读取。.net

 

动做Action

一个将被执行的动做的字符串命名-或者, 对于广播意图而言, 是发生并被报告的动做。这个意图类定义了一些动做常量, 包含下面这些:

 

常量
 目标组件
 Action
 
ACTION_CALL
 活动
 开始一个电话呼叫
 
ACTION_EDIT
 活动
 显示数据以给用户编辑
 
ACTION_MAIN
 活动
 开始任务的初始活动,没有输入数据也没有输出返回
 
ACTION_SYNC
 活动
 同步服务器与移动设备之间的数据
 
ACTION_BATTERY_LOW
 广播接收器
 电池低电量警告
 
ACTION_HEADSET_PLUG
 广播接收器
 耳机插拔
 
ACTION_SCREEN_ON
 广播接收器
 屏幕开启
 
ACTION_TIMEZONE_CHANGED
 广播接收器
 时区变化
 

经过查看Intent类描述可得到一个通用动做的预约义常量列表。其余动做被定义在Android API的其余地方。你也能够自定义动做字符串来激活应用程序中的组件。那些你所建立的动做字符串应该以应用程序包名做为前缀-例如:

"com.example.project.SHOW_COLOR".

动做很大程度上决定了意图其余部分如何被组织-尤为是数据data和附加字段extras-很像一个方法名决定了一些参数和返回值. 所以, 一个好的想法是使用尽量具体的动做名并和意图的其余字段紧密联系起来。换句话说,为您的组件能处理的意图对象定义一个总体的协议而不是定义一个孤立的动做。

一个意图对象里的动做能够经过setAction()方法设置和经过getAction()方法读取.

 

数据Data

想要操做的数据统一资源标识符(URI)和那种数据的多用途互联网邮件扩展(MIME). 不一样的动做伴随着不一样种类的数据规格。例如,若是动做是ACTION_EDIT,数据字段会包含可编辑文档的URI;若是动做是ACTION_CALL,数据字段会是一个电话号码:含呼叫电话号码的URI;相似的,若是动做是ACTION_VIEW并且数据字段是一个http:URI, 那么接收到的活动将会是下载并显示URI所引用数据的请求。当匹配一个意图到一个能处理数据的组件时,除了它的URI外,一般须要知道数据类型(它的MIME类型)。

好比,一个能显示图片的组件不该该被要求去播放一个声音文件。

在不少状况下,这个数据类型能够从URI里推断出来-尤为是content:URIs, 这意味着数据被存放在设备上并且由一个内容提供者控制着。(参阅separate discussion on content providers). 但类型能够在乎图对象里显示的设置。setData()方法指定数据只能为一个URI,setType()指定它只能是一个MIME类型, 而setDataAndType()指定它同时为URI和MIME类型。URI经过getData()读取,类型则经过getType().

 

目录Category

一个包含关于应该处理这个意图的组件的附加信息的字符串。任意数目的类别描述能够被放到一个意图对象里。和动做同样,意图类定义若干类别常量,包含以下这些:

常量
 含义
 
CATEGORY_BROWSABLE
 目标活动能够被浏览器安全的唤起来显示被一个连接所引用的数据-好比,一张图片或一条e-mail消息。
 
CATEGORY_GADGET
 这个活动能够被嵌入到充当配件宿主的另外的活动里面。
 
CATEGORY_HOME
 这个活动将显示桌面,也就是用户开机后看到的第一个屏幕或者按HOME键时看到的屏幕。
 
CATEGORY_LAUNCHER
 这个活动能够是一个任务的初始活动并被列在应用程序启动器的顶层。
 
CATEGORY_PREFERENCE
 目标活动是一个选择面板。
 

查阅Intent类描述可获取类别的完整列表。

addCategory()方法在一个意图对象中添加了一个目录,removeCategory()删除以前添加的目录,而getCategories()能够获取当前对象的全部类别。

 

附加信息Extras

应该递交给意图处理组件的附加信息键-值对。就像一些动做伴随着特定的数据URIs类型,一些动做则伴随着特定的附加信息。好比,一个ACTION_TIMEZONE_CHANGED意图有一个“时区”附加信息用来区别新的时区,而ACTION_HEADSET_PLUG有一个“状态”附加字段代表耳机有没有插着,以及一个“名字”附加信息来表示耳机的类型。若是你想要建立一个SHOW_COLOR动做,颜色的值将被设置在一个附加的键-值对中。

意图对象有一系列的put...()方法来插入各类不一样的附加数据和一个相似的用来读取数据的get...()方法系列。这些方法与Bundle对象的方法类似。事实上,附加信息能够被看成一个Bundle经过使用putExtras()和getExtras()方法安装和读取。

标志Flags

各类类型的标志. 许多标志用来指示Android系统如何去加载一个活动(例如,哪一个是这个活动应该归属的任务)和启动后如何对待它(好比,它是否属于当前活动列表),全部这些列表都在乎图类中定义了。

Android系统以及这个平台上的应用程序利用意图对象来发送源于系统的广播以及激活系统定义的组件。要查阅如何组织一个意图去激活一个系统组件,请咨询引用中的意图列表list of intents。

 

意图解析Intent Resolution

意图能够被分红两组:

显式意图  经过名字指明目标组件(这个组件名字字段component name field, 前面提到过, 有一个数值集)。既然组件名称一般不为其余应用程序的开发者所了解,显式意图典型的被用做应用程序的内部消息-例如一个活动启动一个附属服务或姊妹活动。
隐式意图  不命名目标组件(组件名称字段为空)。隐式意图常常用来激活其余应用程序的组件。
Android递交一个显式的意图给一个指定目标类的实例。意图对象中的组件名称惟一的肯定哪一个组件应该获取这个意图。隐式意图须要一个不一样的策略。在没有指定目标的状况下,Android系统必须找到最合适的组件来处理这个意图-单个活动或者服务来执行这个请求动做或者一系列的广播接收器来应对广播通告。

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

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

动做
数据(URI以及数据类型)
类别

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

 

意图过滤器Intent filters

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

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

 

过滤器与安全Filters and security

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

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

三个测试详细描述以下:

动做测试Action test

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

    

    

    

     . . .

 

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

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

·         若是这个过滤器没有列出任何动做,那意图就没有什么可匹配的,所以全部的意图都会测试失败。没有意图可以经过这个过滤器。

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

类别测试Category test

一个意图过滤器 元素也列举了类别做为子元素。好比:

    

    

     . . .

注意前面描述的动做和类别常量没有在清单文件中使用。相反使用了完整的字符串。好比,对应于前述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

就像动做和类别,一个意图过滤器的数据规格被包含在一个子元素中。并且这个子元素能够出现屡次或一次都不出现。例如:

    

    

     . . .

 

每一个数据元素能够指定一个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能够匹配上。固然,一个过滤器中的路径规格能够包含通配符,这样只须要部分匹配便可。

数据元素的类型属性指定了数据的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:模式。这是一个典型状况。好比,一个以下的数据元素,告诉Android这个组件能从内容提供者获取图片数据并显示:

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

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

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

    

    

 

 

使用意图匹配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/iefreer/archive/2009/08/17/4456376.aspx

相关文章
相关标签/搜索