Intent 和 Intent Filter

 

Android 应用程序中有三大核心组件: Activity,  Service, Broadcast Receiver  都是通过被称之为意图的消息运行。 意图本身一个 Intent 对象,它是对要执行的操作抽象描述,  但是,对于broadcasts来说,则表述一个事情已经发生并且正在被广播。对以下这三个组件传递意图分别有不同的机制:

  • 传入一个Intent对象到 Context.startActivity() 或者 Activity.startActivity ForResult() 去运行一个Activity.(可以在通过此方式启动后的Activity中调用 Activity.setResult() 设置结果参数,该参数将会在启动当前activityactivity中被接收---可以通过onActivityResult(int requestCode, int resultCode, Intent data) 接收)
  • 传入一个Intent对象到 Context.startService(intent) 去启动一个service 或者 传入一个新的指令到正在运行的service中。另外,还可以通过 Context.bindService(intent) 去绑定一个Service。(在调用组件和目标Service 建立一个连接)
  • 传入一个Intent对象传入到Context.sendBroadcast() , Context.sendOrderedBroadcast(), Context.sendStickyBroadcast()等方法,则intent将被传递给所有已经被注册的broadcast receiver中。

在以上的三种情况下,当Intent被传递出后,Android系统会找到适合的activityservice,或者是多个broadcast receiver去响应这个intent,这三种情况不会存在重叠的部分,它们相互独立,互不干扰。(调用Context.startActivity() intent只会被相应的activity接收到,而不会service接收)

 

Intent Object

一个Intent对象是一个信息包。它包含了要接收此Intent的组件所需要的信息(例如需要的动作(actuion) 和动作需要的data信息)和 android 系统需要的信息(要处理此Intent的组件的类别category和怎样启动它(flags) )

总的来说,Intent Object 主要包括以下信息:

Component name(组件名称)

                  

 处理Intent 的组件名称。此字段是一个 ComponentName object---它是目标组件的完整限定名(包名+类名).组件名称是可选的,如果设置了,那么intent将会被传给对应的类实例中。如果没有,android系统会利用intent对象中的其它信息将其定位到一个合适的目标组件中。

设置 component name 可以通过 setCompont(), setClass() 或者 setClassName() 进行设置。 通过getComponent() 可以进行读取。

Action(动作

         一个字符串,代表要执行的动作。 -- 对于 broadcase intents 来说,表示已经发生并且被报告的动作。Intent 类中 定义了许多动作常量。 如下:

常量目标组件
动作
ACTION_CALLactivity发起一个电话呼叫.
ACTION_EDITactivity显示数据给用户来编辑.
ACTION_MAINactivity将该activity作为一个task的第一个activity启动,不传入参数也不没有返回值.
ACTION_SYNCactivity将设备上的数据和一个服务器同步.
ACTION_BATTERY_LOWbroadcast receiver发出电量不足的警告.
ACTION_HEADSET_PLUGbroadcast receiver一个耳机正被插入或者拔出.
ACTION_SCREEN_ONbroadcast receiver屏幕被点亮.
ACTION_TIMEZONE_CHANGEDbroadcast receiver时区设置改变.

你也可以定义自己的 action strings 来启动程序。自定义的action 应该包含包名作为前缀: 例如"com.example.project.SHOW_COLOR".

Action 很大程度上决定 Intent余下部分的结构。 ---- 特别是:data extras 两个字段。就像一个方法的方法名通常决定了方法的参数和返回值。 基于这个原因,应该给action 命名一个尽可能明确的名字。 可以通过 setAction() 设置action,通过 getAction() 获取action

 

 

数据(Data

         Data属性有两部分构成: 数据URI 和 数据MIME type action的定义往往决定了data该如何定义。 例如: 如果  一个Intent action  ACTION_EDIT 那么它对应的data 应该包含待编辑的数据的URI . 如果一个action 为:ACTION_CALL ,那么data 应该为  tel: 电话号码的URI .  类似的, 如果action ACTION_VIEW 那么data 应该为: http: URI , 接收到的activity 将会下载并显示相应的数据。

当一个Intent 和 有能力处理此Intent的组件进行匹配时, 除了 dataURI以外,了解data的类型(MIME Type)也很重要。 例如: 一个显示图片的组件 不应该去播放声音文件。

许多情况下, data type 可以从 URI中推测出。 尤其是: URI =   content:   URIs这时候数据通常是位于本设备上而且是由某个 content provider来控制的。即便如此,我们仍然可以明确的在 Intent object上设置一个 data type.  setData() 方法只能设置 URI, setType() 设置 MIME type, setDataAndType() 可以对二者都进行设置,   获取 URI data type 可分别调用 getData() getType() 方法。

 

Category

 

一个字符串, 包含了处理该Intent的组件的种类信息, 起着对action的补充说明作用.

一个Intent对象可以有任意多个 category。和action 一样, 在Intent class 中也定义了几个 category 常量。。 如下:

Constant

Meaning

CATEGORY_BROWSABLE

目标Activity可以使用浏览器显示数据

CATEGORY_GADGET

The activity can be embedded inside of another activity that hosts gadgets.

activity可以被包含在另外一个装载小工具的activity.

CATEGORY_HOME

The activity displays the home screen, the first screen the user sees when the device is turned on or when the HOME key is pressed.

CATEGORY_LAUNCHER

The activity can be the initial activity of a task and is listed in the top-level application launcher.

可以让一个activity出现在launcher

CATEGORY_PREFERENCE

The target activity is a preference panel.

activity是一个选项面板

addCategory() 添加一个 category

removeCategory() 删除一个 category()

getCategorys() 获取所有的category()

Extras

为键-值对形式的附加信息. 例如ACTION_TIMEZONE_CHANGEDintent有一个"time-zone"附加信息来指明新的时区, ACTION_HEADSET_PLUG有一个"state"附加信息来指示耳机是被插入还是被拔出.

intent对象有一系列put...()set...()方法来设定和获取附加信息. 这些方法和Bundle对象很像. 事实上附加信息可以使用putExtras()getExtras()作为Bundle来读和写.

 

Flags

有各种各样的标志,许多指示Android系统如何去启动一个活动(例如,活动应该属于那个任务)和启动之后如何对待它(例如,它是否属于最近的活动列表)。所有这些标志都定义在Intent类中。

 

Intent Resolution

 

Intent 有两种形式:

显示意图指定一个目标组件通过其name( Component name field), 由于组件名称通常不会被其它应用程序的开发者知道。所以,显示意图通常用在应用程序内部消息。----如:一个Activity 启动一个从属的service或者启动另一个activity

隐式意图不指定目标组件名称(component name 是空的)隐式意图通常用于去激活其它应用程序的组件

 

Android 传递了一个显示意图给一个被指定的目标类的实例 。被传递的 intent object 只是定义了component name -- 它决定了将会有那个组件去处理这个intent

 

针对隐式意图需要不同的策略。在缺乏一个被指定的target的情况下,android系统必须找到最适合的组件去处理这个intent ---- 一个单一的activity 或者 service 去执行一个请求动作或者一组broadcase receiver 去响应广播通知.

它通过将intent 对象中的内容 和 意图过滤器(intent filters)进行比较。android系统根据intent filter打开可以接收intent的组件. 如果一个组件没有intent filter, 那么它只能接受显式intent. 如果有, 则能同时接受二者.

Only three aspects of an Intent object are consulted when the object is tested against an intent filter:

当一个intentintent过滤器进行比较时只会考虑以下三方面:

action 
data (both URI and data type) 
category 

 

Intent filters

要告诉android系统哪个intent它们可以处理,activitiesservices,和 broadcast receivers 必须设置一个或者多个intent过滤器。每个过滤器描述了组件的一种能力,它过滤掉不想要的intent,留下想要的。显示意图则不用考虑这些。

一个过滤器中包含 一个Intent object 中的三个属性 action,data,catrgory 。一个隐式意图必须要通过这三项测试才能传递到 包含该过滤器的组件中。

 

测试1: 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>

如实例所示,当一个intent对象只能命名一个单一的action,一个过滤器则可以列出多个action。这个列表也可以是空的, 一个过滤器必须包含一个  <action>  element ,否则它将阻止所有的intents要通过这个测试,在intent被指定的action必须匹配在过滤器中所列的action的其中之一。如果一个intent对象或者过滤器没有指定action。 结果如下 :

  • 如果一个filter 没有指定任何action ,那么则没有任何intent会被匹配。所以,所有的intent将不会通过此测试。
  • 另一方面,如果一个intent对象没有指定任何action,那么将自动通过此测试—只要这个过滤器中有至少一个action      

测试2:Category test

 

<intent-filter . . . >

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

 

要通过category测试, Intent对象中包含的每个category必须匹配filter中的一个。Filter可以列出额外的category,但是不能漏掉 intent 对象包含的任意一个category

原则上,一个没有任何categorys Intent object 将总是通过此测试。大多数情况下是正确的。然而,也有例外,android对待所有传入 startActivity() 中的隐式视图,都认为它们至少包含了一个 category --- "android.intent.category.DEFAULT". . 因此,希望接收这些隐式意图的activities必须在在它们的 intent filters 中包含”android.intent.category.DEFAULT” ..有(对于包含"android.intent.action.MAIN" and "android.intent.category.LAUNCHER"filter 则是例外。因为它们标记了此activity开启了一个新的task 和 将出现在 auncher screen。它们也可以包含“com.intent.category.DEFAULT,但没必要)

 

测试3:Data test

类似于action, categories, data也是 intent filter 中的一个子节点, 可以设置多个 data节点,也可以一个不设置。

<intent-filter . . . >

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

每个< data > 元素可以指定一个 URI 和 一个 data type (MIME media type)  . URI 有以下几个属性组成 : schema, host,port,path

 Schema://host:port/path

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

其中 schema=content     host=com.example.project     Port=200          Path= folder/subfolder/etc

主机 host  port 一起组成了URI  authority,如果没有指定 host,那么port将被忽略。

<data>节点中的属性都是可选的,但它们并非相互独立。要使一个authority 有意义,必须要指定 scheme 。 要是 path 有意义, scheme authorityhost:port) 必须指定。

 Intent对象中的URI intent filter 进行比较时,它只会进行部门比较。 例如: 如果一个 filter 只指定了一个scheme , 那么所有包含该schemeURI都会匹配。 如果一个filter只指定了 scheme authority ,没有path, 那么所有包含此scheme authority 将会匹配。如果一个filter指定了一个scheme,authority, 和一个path, 那么只有包含同样的 scheme,authoritym,path会匹配。 但是,对于path,我们可以使用通配符进行部门匹配。

<data>节点的 type 属性指定了 dataMIME type。 它比在filter中的URI 更常见 intent对象和filter都可以使用 “*” 通配符作为子类型 例如: "text/*" or "audio/*"--- 表示所有子类型都匹配。

data test 会将 intent对象中的URI data type filter指定的都进行比较。 规则如下:

a)         如果一个intent 没有指定URI data type , 那么如果filter中也是同样,则通过测试。

b)         如果一个iintent URI 但是没有 data type(或者是data type不能从uri中推断出来 ) 只能通过这样的filter:  uri匹配, 并且不指定类型. 这种情况限于类似mailto:tel:这样的不指定实际数据的uri.

c)         如果一个intent 包含 data type 但是没有 uri ,那么 filter中列出相同的data type 并且没有指定URI 则通过测试。

d)         如果一个intent包含一个URI data type (或者data type 可以从URI中推断出来),那么filter列出的有相同data type intent对象的uri要么和filter中的uri匹配,要么intenturi content: or file: 并且filter不指定uri

如果一个Intent 可以通过多个activity或者filterfilter,那么用户将会被询问需要激活哪个组件。 如果一个都没有的话,将会抛出异常。

如果一个intent在与一个activity的intent filers 进行匹配时,通过了以上三种测试(action,category,data)那么将会被匹配。

Common cases

这个规则是针对 data test 中的规则d) ,它反映出组件可以从一个file或者content provider 获取本地数据。因此,filters 可以是设置data type并且没有必要明确的将 scheme 命名为  content:  file:

下面的 <data>元素,告诉android该组件可以从content provider中获取image data 并显示。

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

考虑当用户在一个web page上点了一个链接后,浏览器应用程序做了什么。 它首先会试图去显示该数据(当做一个html页来处理)。如果它不能显示此数据,它会使用一个设置 scheme data type 的隐式意图 去启动一个能显示此数据的activity。如果没有找到接受者,它会调用下载管理器去下载该数据,然后将其放在content provider的控制之下,这样很多activitys (那些之命名了datatype)可以处理该数据

 

大部分应用程序还有一种方式可以单独启动,不用去引用特别的数据。那些要启动应用程序的activity 必须 设置 "android.intent.action.MAIN" 作为action

如果还要显示在程序启动器上则必须设置 "android.intent.category.LAUNCHER" cateegory.

 

<intent-filter . . . >
   
<action android:name="code android.intent.action.MAIN" />
   
<category android:name="code android.intent.category.LAUNCHER" />
</intent-filter>

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值