Android Intent决议(Intent Resolution)

Intent决议(Intent Resolution)

 

Intent类型

  Intent可以被分为两类:

  显式Intent:通过名字指定了目标组件。由于一般是不知道其他应用中的组件名的,所以显式Intent主要用在应用内部。

  隐式Intent:隐式的Intent没有对目标命名。隐式的Intent经常被用来启用其他应用中的组件。

 

  当Android向目标类的实例传输一个显式的intent,这时Intent对象中只有component name决定哪个组件可以得到这个intent。

  但是隐式的intent需要一种不同的策略。因为没有指定目标,Android系统必须发现最适合处理这个intent的组件——一个单独的activity或者service去执行指定的动作或者一个broadcast receiver的集合去响应广播通知。它是通过比较Intent对象和intent filter的内容来实现这种选择的。

  intent filter是一些和组件相关的结构,可以接收intent。

  这些Filter广告了组件的各种能力,并且划定了它可以处理的intent,它们为组件提供了接收指定类型的隐式intent的可能。

  如果一个组件没有任何的intent filter,那么它只能接收显式的intent。

  一个有filter的组件可以接收显式和隐式的intent。

 

Intent filter

  为了告知系统哪一些隐式的intent可以被处理,activity,service和broadcast receiver拥有一个或多个intent filter。

  每一个filter描述了组件的一种能力,和一个这个组件愿意接收的intent的集合。

  它实际上的效果是过滤了特定类型的intent,将不想要的intent排除在外,但是也只能排除不想要的隐式类型的intent,显式的intent可以直接被传递到它的目标对象,不管它包含什么,filter是不会被查询的。

  但是一个隐式的intent只能在能够通过这个组件的filter之一的时候传递到这个组件。

  一个组件对于它可以做的各种工作拥有各种独立的filter。

  一个intent filter就是一个IntentFilter类的对象,但是,由于Android系统必须在启动一个组件前知道它的能力,intent filter通常不是在Java代码中建立的,而是在应用的manifest文件中(AndroidManifest.xml),作为<intent-filter> 元素。

  一个例外的情况就是broadcast receiver的filter,它们是通过Context.registerReceiver()方法动态注册的,它们将会被直接作为IntentFilter对象创建。

 

  当一个Intent对象和一个intent filter进行测试时,Intent对象中只有三个方面会被参考:

  action

  data(URI和数据类型)

  category

  当决议那个组件接收intent时,extras和flags是不起作用的。

  一个filter含有与Intent对象中的action,data,category平行的域,一个隐式的intent将会测试所有这三个域。

  为了传递到含有filter的组件,intent对象必须通过所有这三个测试。

  如果其中的一个测试失败了,Android系统将不会把这个intent对象传递到这个组件,至少不会是基于那个filter的组件

  然而,由于一个组件可以拥有多个intent filter,一个intent对象可能没有通过其中的一个filter,但是它可能通过另一个。

 

三种测试

 

Action test

  在manifest中,<intent-filter>元素将动作作为其<action>子元素列出:

<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>

 

  一个filter可以列出多个动作,这个列表不能为空,即一个filter应该至少包含一个动作否则它将会阻挡任何的intent

  为了通过这个测试,intent对象中指定的动作应该和列出的动作之一匹配,如果intent对象或filter没有指定动作,结果将会如下:

  1.如果是filter没有列出任何动作,没有东西让intent来匹配,所以所有的intent都将会在测试中失败。没有任何intent可以通过这个测试

  2.另一方面,如果一个intent对象没有指定动作,那它将自动地通过测试。(只要filter中含有至少一个动作)。

 

Category test

  <intent-filter>也将分类作为其子元素列出,如:

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

 

  如果一个intent对象想通过category test,那么在intent对象中的每一个分类都必须和filter中的一个分类匹配

  Filter可以列出多余的分类,但是不能忽略intent中的任何一个分类。

  原则上来说,一个不带有任何category的intent对象应该总是能够通过测试。

  但是有一个例外,Android将所有传入startActivity()方法的隐式intent看作它们至少含有一个category: "android.intent.category.DEFAULT" (the CATEGORY_DEFAULT constant)。

  所以,想要收到隐式intent对象的activity必须在它们的intent filter中包含 "android.intent.category.DEFAULT" 。(包含"android.intent.action.MAIN" 和 "android.intent.category.LAUNCHER"的filter是一个例外,它们可以包含"android.intent.category.DEFAULT",但是它们没有必要这样做。)

 

Data test

  和动作和分类一样,数据也是作为子标签出现,也可以不出现或出现多次。如:

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

 

  每一个<data>元素可以指定一个URI和一个数据类型(MIME media type)。

  每一个URI包含下列属性:

  scheme, host, port, path

  如:

  scheme://host:port/path

  例如,在下面的URI中:

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

  the scheme is "content", the host is "com.example.project", the port is "200", and the path is "folder/subfolder/etc".

  The host and port together constitute the URI authority; if a host is not specified, the port is ignored.

  Each of these attributes is optional, but they are not independent of each other: For an authority to be meaningful, a scheme must also be specified. For a path to be meaningful, both a scheme and an authority must be specified

 

  当一个intent对象中的URI和filter中的URI比较时,它仅仅和filter中实际提到的URI部分进行比较。

  比如,一个filter仅仅指定了scheme,那么所有有那个scheme的URI都和这个filter匹配。

  Filter中的path可以包含通配符(wildcards)。

  

  <data>元素中的type属性指定了数据的MIME type,它在filter中比URI更常见。

  Intent对象和filter都可以使用通配符*去表示子类型,如"text/*" or "audio/*" — indicating any subtype matches

 

  数据测试需要测试URI和数据类型,规则如下:

  a.一个intent对象,如果既不包含URI,也不包含数据类型,那么仅当filter也都不包含时,可以通过测试。

  b.如果一个intent对象仅包含一个URI,不包含数据类型,(并且从URI中也不能得到数据类型),那么仅当这个URI和filter中的URI匹配,并且filter中也不包含数据类型时,可以通过测试。(This will be the case only for URIs like mailto: and tel: that do not refer to actual data.)

  c.一个intent对象如果只包含数据类型不包含URI,那么仅当filter包含同样的数据类型并且不包含任何URI时可以通过测试。

  d.一个intent对象如果同时包含URI和数据类型,(或者是可以从URI中推断出的数据类型),那么仅当它的数据类型和filter中的一个数据类型匹配时它可以通过数据类型部分的测试,如果要通过URI部分的测试,一种情况是它的URI和filter中的匹配,另一种情况是intent包含有content:或者file:URI而filter不包含URI。换句话说,如果一个filter只指定了数据类型,组件是预定义地支持content:或者file:数据的。

 

  如果一个intent可以通过多个activity或service的filter,用户将被询问,到底要选择哪个组件来启动;如果没有目标被发现,将会产生一个异常。

 

参考资料

  官方文档:

  http://developer.android.com/reference/android/content/Intent.html

  http://developer.android.com/guide/components/intents-filters.html

  博客:

  http://www.cnblogs.com/feisky/archive/2010/01/16/1649081.html?t=1354802353061

 

 

posted @ 2013-03-18 13:58  圣骑士wind  阅读(1602)  评论(1编辑  收藏  举报