三种应用程序基本组件——activity, service和broadcast receiver——是使用称为intent的消息来激活的。Intent消息传递是一种组件间运行时绑定的机制. intent是Intent对象, 它包含了须要作的操做的描述, 或者, 对于广播来讲, 包含了正在通知的消息内容. 对于向这三种组件发送intent有不一样的机制: html
在上述三种状况下, android系统会本身找到合适的activity, service, 或者 broadcast receivers来响应intent. 三者的intent相互独立互不干扰. android
一个intent对象包含了接受该intent的组件的信息(例如须要的动做和该动做须要的数据)和android系统所须要的信息(例如该组件的类别,以及如何启动它). 具体的说: windows
组件名称
组件名称是可选的. 若是设定了的话, Intent对象会被传给指定的类的一个实例. 若是不设定, 则android使用其它信息来定位合适的目标. 浏览器
组件名称是使用setComponent(), setClass(),或 setClassName()来设定, 使用 getComponent()来获取. 安全
Action常量 | 目标组件 |
动做 |
---|---|---|
ACTION_CALL | activity | 发起一个电话呼叫. |
ACTION_EDIT | activity | 显示数据给用户来编辑. |
ACTION_MAIN | activity | 将该activity做为一个task的第一个activity启动,不传入参数也不指望返回值. |
ACTION_SYNC | activity | 将设备上的数据和一个服务器同步. |
ACTION_BATTERY_LOW | broadcast receiver | 发出电量不足的警告. |
ACTION_HEADSET_PLUG | broadcast receiver | 一个耳机正被插入或者拔出. |
ACTION_SCREEN_ON | broadcast receiver | 屏幕被点亮. |
ACTION_TIMEZONE_CHANGED | broadcast receiver | 时区设置改变. |
你也能够定义本身的action字符串用来启动你的应用程序. 自定义的action应该包含应用程序的包名.例如"com.example.project.SHOW_COLOR". 服务器
action很大程度上决定了intent的另外部分的结构, 就像一个方法名决定了它接受的参数和返回值同样. 所以, 最好给action一个最能反映其做用的名字. 网络
一个intent对象中的action是使用getAction()和setAction()来读写的. app
Data
当将一个intent和一个组件相匹配时, 除了URI外数据类型也很重要. 例如, 一个显示图片的程序不该该用来处理声音文件. 编辑器
数据类型经常能够从URI推断, 特别是content:URI, 它表示该数据属于一个content provider. 但数据类型也能够被intent对象显示声明. setData()方法设置URI, 而setType()方法指定MIME类型, setDataAndType()设置数据URI和MIME类型. 它们可使用getData()和getType()来读取. ide
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
intent对象有一系列put...()和set...()方法来设定和获取附加信息. 这些方法和Bundle对象很像. 事实上附加信息可使用putExtras()和getExtras()做为Bundle来读和写.
Flags各类标志. 不少标志指示android系统如何启动一个activity(例如该activity属于哪一个任务)和启动后如何处理它(例如, 它是否属于最近activity列表中).
android系统和应用程序使用intent对象来送出系统广播和激活系统定义的组件.
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解析中没有用.
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对象只能指定一个action, 而一个intent filter能够指定多个action. action列表不能为空, 不然它将组织全部的intent.
一个intent对象的action必须和intent filter中的某一个action匹配, 才能经过.
若是intent filter的action列表为空, 则不经过.
若是intent对象不指定action, 而且intent filter的action列表不为空, 则经过.
Category 测试
<intent-filter . . . >
<category android:name="android.intent.category.DEFAULT" />
注意前面说到的对于action和category的常数是在代码中用的,而不是manifest文件中用的. 例如,CATEGORY_BROWSABLE常数对应xml中的表示为"android.intent.category.BROWSABLE".
一个intent要经过category测试, 那么该intent对象中的每一个category都必须和filter中的某一个匹配.
理论上来讲, 一个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>元素指定了一个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测试的规则以下:
若是一个intent能够经过多于一个activity或者service的filter, 那么用户可能会被询问须要启动哪个. 若是一个都没有的话, 那么会抛出异常.
上述的最后一个规则(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 . . . >
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().
记事本示例程序让用户能够浏览一个笔记列表, 查看, 编辑, 删除和增长笔记. 这一节关注该程序定义的intent filter.
在其manifest文件中, 记事本程序定义了三个activity, 每一个有至少一个intent filter. 它还定义了一个content provider来管理笔记数据. manifest 文件以下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
第一个activity, NoteList, 和其它activity不一样, 由于它操做一个笔记的目录(笔记列表), 而不是一个单独的笔记. 它通常做为该程序的初始界面. 它能够作如下三件事:
该filter声明了记事本应用程序的主入口. 标准的MAIN action是一个不须要任何其它信息(例如数据等)的程序入口, LAUNCHER category表示该入口应该在应用程序启动器中列出.
该filter声明了改activity能够对一个笔记目录作的事情. 它容许用户查看或编辑该目录(使用VIEW和EDIT action), 或者选取特定的笔记(使用PICK action).
<data>元素的mimeType指定了这些action能够操做的数据类型. 它代表该activity能够从一个持有记事本数据的content provider(vnd.google.note)取得一个或多个数据项的Cursor(vnd.android.cursor.dir).
注意该filter提供了一个DEFAULT category. 这是由于 Context.startActivity() 和Activity.startActivityForResult()方法将全部的intent都做为做为包含了DEFAULT category来处理, 只有两个例外:
所以, 除了MAIN和LAUNCHER的filter以外, DEFAULT category是必须的.
这个filter描述了该activity可以在不须要知道目录的状况下返回用户选择的一个笔记的能力. GET_CONTENT action和PICK action相相似. 在这二者中, activity都返回用户选择的笔记的URI. (返回给调用startActivityForResult()来启动NoteList activity的activity.) 在这里, 调用者指定了用户选择的数据类型而不是数据的目录.
这个数据类型, vnd.android.cursor.item/vnd.google.note, 表示了该activity能够返回的数据类型 -- 一个笔记的URI. 从返回的URI, 调用者能够从持有笔记数据的content provider(vnd.google.note)获得一个项目(vnd.android.cursor.item)的Cursor.
也就是说, 对于PICK来讲, 数据类型表示activity能够给用户显式的数据类型.对于GET_CONTENT filter, 它表示activity能够返回给调用者的数据类型.
下列intent能够被NoteList activity接受:
action: android.intent.action.MAIN
第二个activity, NoteEditor, 为用户显示一个笔记并容许他们编辑它. 它能够作如下两件事:
这个activity的主要目的是使用户编辑一个笔记--VIEW或者EDIT一个笔记. (在category中,EDIT_NOTE是EDIT的同义词.) intent包含匹配MIME类型vnd.android.cursor.item/vnd.google.note的URI--也就是某一个特定的笔记的URI. 它通常来讲是NoteList activity中的PICK或者GET_CONTENT action返回的.
像之前同样,该filter列出了DEFAULT category.
该activity的第二个目的是使用户可以建立一个新的笔记, 并插入到已存在的笔记目录中. 该intent包含了匹配vnd.android.cursor.dir/vnd.google.note的URI, 也就是笔
有了这些能力, NoteEditor就能够接受如下intent:
action: android.intent.action.VIEW最后一个activity, TitleEditor, 容许用户编辑笔记的标题. 这能够经过直接调用activity(在intent中设置组件名称)的方式来实现. 可是这里咱们用这个机会来展现如何在已有数据上进行另外的操做(相似于windows中的打开方式->程序列表 -- 译者注):
<intent-filter android:label="@string/resolve_title">
除了支持DEFAULT category以外,title编辑器还支持了另外两个category: ALTERNATIVE和SELECTED_ALTERNATIVE. 这些category标志着activity能够在选项菜单中呈现给用户(就像LAUNCHER category表示activity能够在程序启动器中同样). 注意filter还提供了一个显示标签(android:label="@string/resolve_title")来更好的控制用户在选项菜单中看到的内容.
有了这些能力, 如下的intent就能够被TitleEditor接受:
action: com.android.notepad.action.EDIT_TITLE