intents and intent Filters

来源:互联网 发布:8080端口服务打开 编辑:程序博客网 时间:2024/05/06 16:51

转自:http://blog.csdn.net/gaohongijj/article/details/7443690

 

三种应用程序基本组件——activity, service和broadcast receiver——是使用称为intent的消息来激活的。Intent消息传递是一种组件间运行时绑定的机制. intent是Intent对象, 它包含了需要做的操作的描述, 或者, 对于广播来说, 包含了正在通知的消息内容. 对于向这三种组件发送intent有不同的机制:

  • 使用Context.startActivity() Activity.startActivityForResult(), 传入一个intent来启动一个activity. 使用Activity.setResult(), 传入一个intent来从activity中返回结果.
  • 将intent对象传给Context.startService()来启动一个service或者传消息给一个运行的service. 将intent对象传给Context.bindService()来绑定一个service.
  • 将intent对象传给 Context.sendBroadcast(),Context.sendOrderedBroadcast(),或者Context.sendStickyBroadcast()等广播方法,则它们被传给 broadcast receiver.

在上述三种情况下, android系统会自己找到合适的activity, service, 或者  broadcast receivers来响应intent. 三者的intent相互独立互不干扰.

Intent Objects Intent对象

一个intent对象包含了接受该intent的组件的信息(例如需要的动作和该动作需要的数据)和android系统所需要的信息(例如该组件的类别,以及如何启动它). 具体的说:

组件名称
为一个ComponentName 对象. 它是目标组件的完整名(例如"com.example.project.app.FreneticActivity")和应用程序manifest文件设定的包名(例如"com.example.project")的组合.前者的包名部分和后者不一定一样.

组件名称是可选的. 如果设定了的话, Intent对象会被传给指定的类的一个实例. 如果不设定, 则android使用其它信息来定位合适的目标.

组件名称是使用setComponent(),setClass(),或 setClassName()来设定, 使用getComponent()来获取.

Action
一个字符串, 为请求的动作命名, 或者, 对于broadcast 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字符串用来启动你的应用程序. 自定义的action应该包含应用程序的包名.例如"com.example.project.SHOW_COLOR".

action很大程度上决定了intent的另外部分的结构, 就像一个方法名决定了它接受的参数和返回值一样. 因此, 最好给action一个最能反映其作用的名字.

一个intent对象中的action是使用getAction()和setAction()来读写的.

Data
需要操作的数据的URI和它的MIME(多用途互联网邮件扩展,Multipurpose Internet Mail Extensions)类型. 例如, 如果action为ACTION_EDIT, 那么Data将包含待编辑的数据URI. 如果action为ACTION_CALL, Data将为tel:电话号码的URI. 如果action为ACTION_VIEW, 则Data为http:网络地址的URI.

当将一个intent和一个组件相匹配时, 除了URI外数据类型也很重要. 例如, 一个显示图片的程序不应该用来处理声音文件.

数据类型常常可以从URI推断, 特别是content:URI, 它表示该数据属于一个content provider. 但数据类型也可以被intent对象显示声明. setData()方法设置URI, 而setType()方法指定MIME类型, setDataAndType()设置数据URI和MIME类型. 它们可以使用getData()和getType()来读取.

Category
一个字符串,包含了关于处理该intent的组件的种类的信息. 一个intent对象可以有任意个category. intent类定义了许多category常数, 例如:
常量含义CATEGORY_BROWSABLE目标activity可以使用浏览器来显示-例如图片或电子邮件消息.CATEGORY_GADGET该activity可以被包含在另外一个装载小工具的activity中.CATEGORY_HOME该activity显示主屏幕,也就是用户按下Home键看到的界面.CATEGORY_LAUNCHER该activity可以作为一个任务的第一个activity,并且列在应用程序启动器中.CATEGORY_PREFERENCE该activity是一个选项面板.

addCategory()方法为一个intent对象增加一个category, removeCategory删除一个category, getCategories()获取intent所有的category.

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

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

Flags

各种标志. 很多标志指示android系统如何启动一个activity(例如该activity属于哪个任务)和启动后如何处理它(例如, 它是否属于最近activity列表中).

android系统和应用程序使用intent对象来送出系统广播和激活系统定义的组件.

Intent Resolution Intent解析

intent有两种:

  • 显式intent使用名字来指定目标组件. 由于组件名称一般不会被其它开发者所熟知, 这种intent一般用于应用程序内部消息-- 例如一个activity启动一个附属的service或者另一个activity.
  • 隐式intent不指定目标的名称. 一般用于启动其它应用程序的组件.

Android将显式intent发送给指定的类. intent对象中名字唯一决定接受intent的对象.

对于隐式intent, android系统必须找到最合适的组件来处理它. 它比较intent的内容和intent filter.  intent filter是组件的一个相关结构, 表示其接受intent的能力. android系统根据intent filter打开可以接受intent的组件. 如果一个组件没有intent filter, 那么它只能接受显式intent. 如果有, 则能同时接受二者.

当一个intent和intent filter比较时, 只考虑三个属性: action, data, category.

extra和flag在intent解析中没有用.

Intent filters

activity, service和broadcast receiver可以有多个intent filter来告知系统它们能接受什么样的隐式intent. intent filter的名字很形象: 它过滤掉不想接受的intent, 留下想接受的intent. 显式intent无视intent filter.

一个组件对能做的每件事有单独的filter. 例如, 记事本程序的NoteEditor activity有两个filter -- 一个启动并显示一个特定的记录给用户查看或编辑, 另一个启动一个空的记录给用户编辑.

一个intent filter是IntentFilter类的实例, 但是它一般不出现在代码中,而是出现在android Manifest文件中, 以<intent-filter>的形式. (有一个例外是broadcast receiver的intent filter是使用Context.registerReceiver()来动态设定的, 其intent filter也是在代码中创建的.)

一个filter有action, data, category等字段. 一个隐式intent为了能被某个intent filter接受, 必须通过3个测试. 一个intent为了被某个组件接受, 则必须通过它所有的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>

一个intent对象只能指定一个action, 而一个intent filter可以指定多个action. action列表不能为空, 否则它将组织所有的intent.

一个intent对象的action必须和intent filter中的某一个action匹配, 才能通过.

如果intent filter的action列表为空, 则不通过.

如果intent对象不指定action, 并且intent filter的action列表不为空, 则通过.

Category 测试


<intent-filter. . . >

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

注意前面说到的对于action和category的常数是在代码中用的,而不是manifest文件中用的. 例如,CATEGORY_BROWSABLE常数对应xml中的表示为"android.intent.category.BROWSABLE".

一个intent要通过category测试, 那么该intent对象中的每个category都必须和filter中的每一个匹配.category之间是与的关系;

理论上来说, 一个intent对象如果没有指定category的话, 它应该能通过任意的category 测试. 有一个例外: android把所有的传给startActivity()的隐式intent看做至少有一个category: "android.intent.category.DEFAULT". 因此, 想要接受隐式intent的activity必须在intent filter中加入"android.intent.category.DEFAULT". ("android.intent.action.MAIN" 和"android.intent.category.LAUNCHER"的intent 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和一个数据类型. URI每个部分为不同的属性 -- scheme, host, port, path:

scheme://host:port/path

例如, 在如下的URI中:

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

scheme为"content", host为"com.example.project", port为"200", path为"folder/subfolder/etc". host和port一起组成了URI authority. 如果host未指定,则port被忽略.

这些属性都是可选的,但它们并非相互独立: 要使一个authority有意义,必须指定一个scheme. 要使一个path有意义, 必须指定一个scheme和一个authority.

当intent对象中的URI和intent filter中相比较时, 它只和filter中定义了的部分比较. 例如, 如果filter中之定义了scheme,那么所有包含该scheme的URI的intent对象都通过测试.对于path来说,可以使用通配符来进行部分匹配.

<data>元素的type属性指定了数据类型. 它在filter中比在URI中更常见. intent对象和filter都可以使用"*"通配符作为子类型. 例如"text/*" "audio/*"表示所有的子类型都匹配.

data测试的规则如下:

  1. 一个不含uri也不含数据类型的intent对象只通过两者都不包含的filter.
  2. 一个含uri但不含数据类型的intent对象(并且不能从uri推断数据类型的)只能通过这样的filter: uri匹配, 并且不指定类型. 这种情况限于类似mailto:和tel:这样的不指定实际数据的uri.
  3. 一个只包含数据类型但不包含URI的intent只通过这样的filter: 该filter只列出相同的数据类型, 并且不指定uri.
  4. 一个既包含uri又包含数据类型的intent对象只通过这样的filter: intent对象的数据类型和filter中的一个类型匹配, intent对象的uri要么和filter的uri匹配, 要么intent对象的uri为content:或者file:, 并且filter不指定uri.

如果一个intent可以通过多于一个activity或者service的filter, 那么用户可能会被询问需要启动哪一个. 如果一个都没有的话, 那么会抛出异常.

Common cases 常见情况

上述的最后一个规则(d)说明了组件通常可以从文件和content provider中获取数据. 因此, 它们的filter可以只列出数据类型不列scheme. 这是个特殊情况. 下列<data>元素告诉android该组件可以从一个content provider取得图像数据并显示之:


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

由于大部分可用的数据由content provider提供, 指定数据类型但不指定uri的filter是最常见的情况.

另外一个常见的配置是filter具有一个scheme和一个数据类型. 例如, 下列<data>元素告诉android该component可以从网络获取图像数据并显示之:


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

考虑用户点击一个网页时浏览器的动作. 它首先试图显示这个数据(当做一个html页来处理). 如果无法显示, 则创建一个隐式intent, 并启动一个可以处理它的activity. 如果没有这样的activity, 那么它请求下载管理器来下载该数据. 然后它将数据置于一个content provider的控制之下, 这样有很多activity(拥有只有数据类型的filter)可以处理这些数据.

大部分应用程序还有一种方法来单独启动, 不需要引用任何特定的数据. 这些能启动应用程序的activity具有action为"android.intent.action.MAIN" 的filter. 如果它们需要在应用程序启动器中显示, 它们必须指定"android.intent.category.LAUNCHER" 的category.


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

Using intent matching 使用intent匹配

intent和intent filter相匹配, 不仅为了寻找并启动一个目标组件, 也是为了寻找设备上组件的信息. 例如, android系统启动了应用程序启动器, 该程序位于屏幕的顶层, 显示了用户可以启动的程序, 这是通过查找设备上所有的action为"android.intent.action.MAIN" ,category为"android.intent.category.LAUNCHER"的intent filter所在的activity实现的. 然后它显示了这些activity的图标和标题. 类似的, 它通过寻找 "android.intent.category.HOME"的filter来定位主屏幕程序.

应用程序可以用相同的方式来使用intent匹配. PackageManager 有一组query...()方法来寻找接受某个特定intent的所有组件, 还有一系列resolve...()方法来决定响应一个intent的最佳组件. 例如,queryIntentActivities()返回一个activity列表, 这些activity可以执行传入的intent. 类似的还有queryIntentServices()和queryIntentBroadcastReceivers().

原创粉丝点击