这么长时间对intent 一直不是很了解,在网上看了几篇文章,在机子上实验了下,记录下自己的学习。
Android 中提供了 Intent 机制来协助应用间的交互与通讯,或者采用更准确的说法是, Intent 不仅可用于应用程序之间,也可用于应用程序内部的 Activity/Service 之间的交互。 在 Intent 的使用中你看不到直接的函数调用,相对函数调用来说, Intent 是更为抽象的概念,利用 Intent 所实现的软件复用的粒度是 Activity/Service ,比函数复用更高一些,另外耦合也更为松散。
Android 中与 Intent 相关的还有 Action/Category 及 Intent Filter 等,另外还有用于广播的 Intent ,这些元素掺杂在一起,导致初学者不太容易迅速掌握 Intent 的用法。
在SDK 中给出了Intent 作用的表现形式为:
- 通过
Context.startActivity()
orActivity.startActivityForResult()
启动一个 Activity ; - 通过
Context.startService()
启动一个服务,或者通过Context.bindService()
和后台服务交互; - 通过广播方法 ( 比如
Context.sendBroadcast()
,Context.sendOrderedBroadcast()
,Context.sendStickyBroadcast()
) 发给 broadcast receivers 。
Intent 属性的设置 ,包括以下几点:(以下为XML 中定义,当然也可以通过Intent 类的方法来获取和设置)
(1 )Action ,也就是要执行的动作
SDk 中定义了一些标准的动作,包括
onstant | Target component | Action |
| activity | Initiate a phone call. |
| activity | Display data for the user to edit. |
| activity | Start up as the initial activity of a task, with no data input and no returned output. |
| activity | Synchronize data on a server with data on the mobile device. |
| broadcast receiver | A warning that the battery is low. |
| broadcast receiver | A headset has been plugged into the device, or unplugged from it. |
| broadcast receiver | The screen has been turned on. |
| broadcast receiver | The setting for the time zone has changed. |
当然,也可以自定义动作(自定义的动作在使用时,需要加上包名作为前缀,如"com.example.project.SHOW_COLOR
” ),并可定义相应的Activity 来处理我们的自定义动作。
(2 )Data ,也就是执行动作要操作的数据
Android 中采用指向数据的一个URI 来表示,如在联系人应用中,一个指向某联系人的URI 可能为:content://contacts/1 。对于不同的动作,其 URI 数据的类型是不同的(可以设置type 属性指定特定类型数据),如ACTION_EDIT 指定Data 为文件URI ,打电话为tel:URI ,访问 网络为http:URI ,而由content provider 提供的数据则为content:
URIs 。
(3 )type (数据类型),显式指定Intent 的数据类型(MIME )。一般Intent 的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
(4 )category (类 别),被执行动作的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者应该在Launcher 中作为顶级应用出现;而ALTERNATIVE_CATEGORY 表示当前的Intent 是一系列的可选动作中的一个,这 些动作可以在同一块数据上执行。还有其他的为
Constant | Meaning |
| The target activity can be safely invoked by the browser to display data referenced by a link — for example, an image or an e-mail message. |
| The activity can be embedded inside of another activity that hosts gadgets. |
| 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. |
| The activity can be the initial activity of a task and is listed in the top-level application launcher. |
| The target activity is a preference panel. |
(5 )component (组 件),指定Intent 的的目标组件的类名称。通常 Android 会根据Intent 中包含的其它属性的信息,比如action 、data/type 、category 进行查找,最终找到一个与之匹配的目标组件。但是,如果 component 这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent 的其它所有属性都是可选的。
(6 )extras (附加信息),是其它所有附加信息的集合。使用extras 可以为组件提供扩展信息,比如,如果要执行“ 发送电子邮件” 这个动作,可以将电子邮件的标题、正文等保存在extras 里,传给电子邮件发送组件。
理解 Intent 的关键之一是理解清楚 Intent 的两种基本用法:一种是显式的 Intent ,即在构造 Intent 对象时就指定接收者,这种方式与普通的函数调用类似,只是复用的粒度有所差别;另一种是隐式的 Intent ,即 Intent 的发送者在构造 Intent 对象时,并不知道也不关心接收者是谁,这种方式与函数调用差别比较大,有利于降低发送者和接收者之间的耦合。另外 Intent 除了发送外,还可用于广播。
对于显式Intent ,Android 不需要去做解析,因为目标组件已经很明确,Android 需要解析的是那些隐式Intent ,通过解析,将 Intent 映射给可以处理此Intent 的Activity 、IntentReceiver 或Service 。
Intent 解析机制主要是通过查找已注册在AndroidManifest.xml 中的所有IntentFilter 及其中定义的Intent ,最终找到匹配的 Intent 。在这个解析过程中,Android 是通过Intent 的action 、type 、category 这三个属性来进行判断的,判断方法如下:
- 如果 Intent 指明定了 action ,则目标组件的 IntentFilter 的 action 列表中就必须包含有这个 action ,否则不能匹配;
- 如果 Intent 没有提供 type ,系统将从 data 中得到数据类型。和 action 一样,目标组件的数据类型列表中必须包含 Intent 的数据类型,否则不能匹配。
- 如果 Intent 中的数据不是 content: 类型的 URI ,而且 Intent 也没有明确指定它的 type ,将根据 Intent 中数据的 scheme (比如 http: 或者 mailto : ) 进行匹配。同上, Intent 的 scheme 必须出现在目标组件的 scheme 列表中。
- 如果 Intent 指定了一个或多个 category ,这些类别必须全部 出现在组建的类别列表中。比如 Intent 中包含了两个类别: LAUNCHER_CATEGORY 和 ALTERNATIVE_CATEGORY ,解析得到的目标组件必须至少包含这两个类别。
Intent-Filter 的定义
一些属性设置的例子:
<action android:name="com.example.project.SHOW_CURRENT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="video/mpeg" android:scheme="http" . . . />
<data android:mimeType="image/*" />
<data android:scheme="http" android:type="video/*" />
Intent 用法实例
1. 无参数 Activity 跳转
Intent it =
new
Intent(Activity.Main.
this
, Activity2.
class
);
startActivity(it);
2. 向下一个 Activity 传递数据(使用 Bundle 和 Intent.putExtras )
Intent it =
new
Intent(Activity.Main.
this
, Activity2.
class
);
Bundle bundle=
new
Bundle();
bundle.putString("
name
", "
This is from MainActivity!
");
it.putExtras(bundle);
// it.putExtra(“test”, "shuju”);
startActivity(it);
// startActivityForResult(it,REQUEST_CODE);
对于数据的获取可以采用:
Bundle bundle=getIntent().getExtras();
String name=bundle.getString("
name
");
3. 向上一个 Activity 返回结果(使用 setResult ,针对 startActivityForResult(it,REQUEST_CODE) 启动的 Activity )
Intent intent=getIntent();
Bundle bundle2=
new
Bundle();
bundle2.putString("
name
", "
This is from ShowMsg!
");
intent.putExtras(bundle2);
setResult(RESULT_OK, intent);
4. 回调上一个 Activity 的结果处理函数( onActivityResult )
@Override
protected
void
onActivityResult(
int
requestCode,
int
resultCode, Intent data) {
// TODO Auto-generated method stub
super
.onActivityResult(requestCode, resultCode, data);
if
(requestCode==REQUEST_CODE){
if
(resultCode==RESULT_CANCELED)
setTitle("
cancle
");
else
if
(resultCode==RESULT_OK) {
String temp=
null
;
Bundle bundle=data.getExtras();
if
(bundle!=
null
)
temp=bundle.getString("
name
");
setTitle(temp);
}
}
}
应用例子
以Android SDK
中的便笺例子(上面的XML
文件)来说明,Intent
如何定义及如何被解析。这个应用可以让用户浏览便笺列表、查看每一个便笺的详细信息。
例子中的第一个 Activity 是 com.google.android.notepad.NotesList ,它是应用的主入口,提供了三个功能,分别由三个 intent-filter 进行描述:
1 、第一个是进入便笺应用的顶级入口( action 为 android.app.action.MAIN )。类型为 android.app.category.LAUNCHER 表明这个 Activity 将在 Launcher 中列出。
2 、第二个是,当 type 为 vnd.android.cursor.dir/vnd.google.note (保存便笺记录的目录) 时,可以查看可用的便笺( action 为 android.app.action.VIEW ),或者让用户选择一个便笺并返回给调用者( action 为 android.app.action.PICK )。
3 、第三个是,当 type 为 vnd.android.cursor.item/vnd.google.note 时,返回给调用者一个用户选择的便笺 ( action 为 android.app.action.GET_CONTENT ),而用户却不需要知道便笺从哪里读取的。 有了这些功能,下面的 Intent 就会被解析到 NotesList 这个 activity :
- { action=android.app.action.MAIN } :与此 Intent 匹配的 Activity ,将会被当作进入应用的顶级入口。
- { action=android.app.action.MAIN, category=android.app.category.LAUNCHER } : 这是目前 Launcher 实际使用的 Intent ,用于生成 Launcher 的顶级列表。
- { action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes } : 显示 "content://com.google.provider.NotePad/notes" 下的所有便笺的列表,使用者可以遍历列表,并且察看某便笺的详细信息。
- { action=android.app.action.PICK data=content://com.google.provider.NotePad/notes } : 显示 "content://com.google.provider.NotePad/notes" 下的便笺列表,让用户可以在列表中选择一个,然后将选择的便笺的 URL 返回给调用者。
- { action=android.app.action.GET_CONTENT type=vnd.android.cursor.item/vnd.google.note } : 和 上面的 action 为 pick 的 Intent 类似,不同的是这个 Intent 允许调用者(在这里指要调用 NotesList 的某个 Activity )指定 它们需要返回的数据类型,系统会根据这个数据类型查找合适的 Activity (在这里系统会找到 NotesList 这个 Activity ),供用户选择便笺。
第二个 Activity 是 com.google.android.notepad.NoteEditor ,它为用户显示一条便笺,并且允许 用户修改这个便笺。它定义了两个 intent-filter ,所以具有两个功能。第一个功能是,当数据类型为 vnd.android.cursor.item/vnd.google.note 时,允许用户查看和修改一个便签( action 为 android.app.action.VIEW 和 android.app.action.EDIT )。第二个功能是,当数据类型为 vnd.android.cursor.dir/vnd.google.note ,为调用者显示一个新建便笺的界面,并将新建的便笺插 入到便笺列表中( action 为 android.app.action.INSERT )。
有了这两个功能,下面的 Intent 就会被解析到 NoteEditor 这个 activity :
- { action=android.app.action.VIEW data=content://com.google.provider.NotePad/notes/{ID} } : 向用户显示标识为 ID 的便笺。
- { action=android.app.action.EDIT data=content://com.google.provider.NotePad/notes/{ID} } : 允许用户编辑标识为 ID 的便笺。
- { action=android.app.action.INSERT data=content://com.google.provider.NotePad/notes } : 在“ content://com.google.provider.NotePad/notes ” 这个便笺列表中创建一个新的空便笺,并允许用 户编辑这个便签。当用户保存这个便笺后,这个新便笺的 URI 将会返回给调用者。
最后一个 Activity 是 com.google.android.notepad.TitleEditor ,它允许用户编辑便笺的标题。它可以被实现为 一个应用可以直接调用(在 Intent 中明确设置 component 属性)的类,不过这里我们将为你提供一个在现有的数据上发布可选操作的方法。在这个 Activity 的唯一的 intent-filter 中,拥有一个私有的 action : com.google.android.notepad.action.EDIT_TITLE ,表明允许用户编辑便笺的标题。和前面的 view 和 edit 动作一样,调用这个 Intent 的时候,也必须指定具体的便笺( type 为 vnd.android.cursor.item/vnd.google.note )。不同的是,这里显示和编 辑的只是便笺数据中的标题。
除了支持缺省类别( android.intent.category.DEFAULT ),标题编辑器还支持另外两个标准类别: android.intent.category.ALTERNATIVE 和 android.intent.category.SELECTED_ALTERNATIVE 。实现了这两个类别之后,其它 Activity 就可以调用 queryIntentActivityOptions(ComponentName, Intent[], Intent, int) 查询这个 Activity 提供的 action ,而不需要了解它的具体实现;或者调用 addIntentOptions(int, int, ComponentName, Intent[], Intent, int, Menu.Item[]) 建立动态菜单。需要说明的是,在这个 intent-filter 中有一个明确的名称(通过 android:label= "@string/resolve_title" 指定),在用户浏览数据的时候,如果这个 Activity 是数据的一个可选操作,指定明确的名称可以为用 户提供一个更好控制界面。
有了这个功能,下面的 Intent 就会被解析到 TitleEditor 这个 Activity :
- { action=com.google.android.notepad.action.EDIT_TITLE data=content://com.google.provider.NotePad/notes/{ID} } :显示并且允许用户编辑标识为 ID 的便笺的标题。