一、 Intent 作用
Intent被译作意图,其实还是很能传神的,Intent期望做到的,就是把实现者和调用者完全解耦,调用者专心将以意图描述清晰,发送出去,就可以梦想成真,达到目的。


Intent 是一个将要执行的动作的抽象描述,一般来说是作为参数来使用,由Intent来协助完成android各个组件之间的通讯。比如说调用startActivity()来启动一个activity,或者由broadcaseIntent()来传递给所有感兴趣的BroadcaseReceiver, 再或者由startService()/bindservice()来启动一个后台的service.所以可以看出来,intent主要是用来启动其他的activity 或者service,所以可以将intent理解成activity之间的粘合剂。



二、 Intent的构成

要在不同的activity之间传递数据,就要在intent中包含相应的东西,一般来说数据中最基本的应该包括:

-Action:当日常生活中,描述一个意愿或愿望的时候,总是有一个动词在其中。比如:我想三个俯卧撑;我要一部x片;我要一部血泪史,之类云云。在Intent中,Action就是描述看、做、写等动作的,当你指明了一个Action,执行者就会依照这个动作的指示,接受相关输入,表现对应行为,产生符合的输出。在Intent类中,定义了一批量的动作,比如ACTION_VIEWACTION_PICK,之类的,基本涵盖了常用动作,整一个降龙十八掌全集

标准的Activity Actions
ACTION_MAIN作为一个主要的进入口,而并不期望去接受数据
ACTION_VIEW向用户去显示数据
ACTION_ATTACH_DATA用于指定一些数据应该附属于一些其他的地方,例如,图片数据应该附属于联系人
ACTION_EDIT访问已给的数据,提供明确的可编辑
ACTION_PICK从数据中选择一个子项目,并返回你所选中的项目
ACTION_CHOOSER显示一个activity选择器,允许用户在进程之前选择他们想要的
ACTION_GET_CONTENT允许用户选择特殊种类的数据,并返回(特殊种类的数据:照一张相片或录一段音)
ACTION_DIAL拨打一个指定的号码,显示一个带有号码的用户界面,允许用户去启动呼叫
ACTION_CALL根据指定的数据执行一次呼叫
(ACTION_CALL在应用中启动一次呼叫有缺陷,多数应用ACTION_DIAL,ACTION_CALL不能用在紧急呼叫上,紧急呼叫可以用ACTION_DIAL来实现)
ACTION_SEND 传递数据,被传送的数据没有指定,接收的action请求用户发数据
ACTION_SENDTO发送一个信息到指定的某人
ACTION_ANSWER 处理一个打进电话呼叫
ACTION_INSERT插入一条空项目到已给的容器
ACTION_DELETE 从容器中删除已给的数据
ACTION_RUN运行数据,无论怎么
ACTION_SYNC同步执行一个数据
ACTION_PICK_ACTIVITY为已知的Intent选择一个Activity,返回别选中的类
ACTION_SEARCH 执行一次搜索
ACTION_WEB_SEARCH 执行一次web搜索
ACTION_FACTORY_TEST 工场测试的主要进入点,


标准的广播Actions
ACTION_TIME_TICK 当前时间改变,每分钟都发送,不能通过组件声明来接收,只有通过Context.registerReceiver()方法来注册
ACTION_TIME_CHANGED 时间被设置
ACTION_TIMEZONE_CHANGED 时间区改变
ACTION_BOOT_COMPLETED 系统完成启动后,一次广播
ACTION_PACKAGE_ADDED 一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)
ACTION_PACKAGE_CHANGED 一个已存在的应用程序包已经改变,包括包名
ACTION_PACKAGE_REMOVED 一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)
ACTION_PACKAGE_RESTARTED用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播)
ACTION_PACKAGE_DATA_CLEARED用户已经清楚一个包的数据,包括包名(清除包程序不能接收到这个广播)
ACTION_BATTERY_CHANGED电池的充电状态、电荷级别改变,不能通过组建声明接收这个广播,只有通过Context.registerReceiver()注册
ACTION_UID_REMOVED一个用户ID已经从系统中移除


-Data(数据):要事实的具体的数据,一般由一个Uri变量来表示

下面是一些简单的例子:

ACTION_VIEW content://contacts/1 //显示identifier为1的联系人的信息。
ACTION_DIALcontent://contacts/1 //给这个联系人打电话

除了Action和data这两个最基本的元素外,intent还包括一些其他的元素,

- Category(范畴):指定Action范围,这个选项指定了将要执行的这个action的其他一些额外的约束.有时通过Action,配合Data或Type,很多时候可以准确的表达出一个完整的意图了,但也会需要加一些约束在里面才能够更精准。比如,如果你虽然很喜欢做俯卧撑,但一次做三个还只是在特殊的时候才会发生,那么你可能表达说:每次吃撑了的时候,我都想做三个俯卧撑。吃撑了,这就对应着Intent的Category的范畴,它给所发生的意图附加一个约束。在Android中,一个实例是:所有应用的主Activity(单独启动时候,第一个运行的那个Activity...),都需要一个Category为 CATEGORY_LAUNCHER,Action为ACTION_MAIN的Intent。


-Type(数据类型):用于指定类型,以供过滤(比如ACTION_VIEW同时指定为TypeImage,则调出浏览图片的应用).一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行判定。

-Component(组件):当我们常用Action,Data/Type,Category去描述一个意图,这是Android推荐,这种模式称:Implicit Intents. 通过这种模式,提供一种灵活可扩展的模式,给用户和第三方应用一个选择权。比如:一个邮箱软件,大部分功能都好,就是选择图片的功能做的很土,怎么办?如果它采用的是Implicit Intents,那么它就是一个开放的体系了,手机中没有其他图片选择功能的情况下,可以继续使用邮箱默认的,如果有,你可以任意选择来替代原有模块完成这功能,一切都自然而然。但这种模式需要付出性能上的开销,因为毕竟有一个检索过程。于是,Android提供了另一种模式,叫做Explicit Intents ,就需要Component的帮助了。Component就是完整的类名,形如com.xxxxx.xxxx ,一旦指明了,可以直接调用,自然是速度快. 适合在你明确知道这就是一个内部模块的时候,使用它。


-Extras(附加信息):是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。


-Flags(标志位):能识别,有输入,整个Intent基本就完整了,但还有一些附件的指令,需要放在Flags中带过去。顾名思义,Flags是一个整形数,有一些列的标志 位构成,这些标志,是用来指明运行模式的。比如,你期望这个意图的执行者,和你运行在两个完全不同的任务中(或说进程也无妨吧...),就需要设置FLAG_ACTIVITY_NEW_TASK的标志位。


Android 的一个特色就是 application A 的 activity 可以启动 application B 的 activity,尽管 A 和 B 是毫无干系的,而在用户看来,两个场景紧密联系,视觉上二者构成了一个整体。Android 就是把这种误觉定义为 Task,它既不是 class,也不是 AndroidMainifest.xml 中的一个元素。从表现上看 Task 就像是一个 stack,一个一个的 activity 是构成 stack 的元素,做着入栈 (push) 和出栈 (pop-up)这样简单重复性的劳动。

默认的规则总是满足大多数的应用场景,但是也总会有一些例外打破习以为常的惯例。Task 的默认规则同样并非牢不可破,修改的方法还是有的。借助 Intent 中的 flag 和 AndroidMainifest.xml 中 activity 元素的属性,就可以控制到 Task 里 Activity 的关联关系和行为。

在 android.content.Intent 中一共定义了20种不同的 flag,其中和 Task 紧密关联的有四种:

FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
在使用这四个 flag 时,一个 Intent 可以设置一个 flag,也可以选择若干个进行组合。

默认情况下,通过 startActivity() 启动一个新的 Activity,新的 Activity 将会和调用者在同一个 stack 中。但是,如果在传递给 startActivity() 的 Intent 对象里包含了 FLAG_ACTION_NEW_TASK,情况将发生变化,系统将为新的 Activity “寻找”一个不同于调用者的 Task。不过要找的Task 是不是一定就是 NEW 呢?如果是第一次执行,则这个设想成立,如果说不是,也就是说已经有一个包含此 Activity 的Task 存在,则不会再启动 Activity。

如果 flag 是 FLAG_ACTIVITY_CLEAR_TOP,同时当前的 Task 里已经有了这个 Activity,那么情形又将不一样。Android 不但不会启动新的 Activity 实例,而且还会将 Task 里 该 Activity 之上的所有 Activity 一律结束掉,然后将 Intent 发给这个已存在的 Activity。Activity 收到 Intent 之后,可以在 onNewIntent() 里做下一步的处理,也可以自行结束然后重新创建自己。如果 Activity 在 AndroidMainifest.xml 里将启动模式设置成multiple,– 默认模式,并且 Intent 里也没有设置 FLAG_ACTIVITY_SINGLE_TOP,那么它将选择后者。否则,它将选择前者。FLAG_ACTIVITY_CLEAR_TOP 还可以和 FLAG_ACTION_NEW_TASK 配合使用。

如果 flag 设置的是 FLAG_ACTIVITY_SINGLE_TOP,则意味着如果 Activity 已经是运行在 Task 的 top,则该 Activity 将不会再被启动。


三、 intent的解析

在应用中,我们可以以两种形式来使用Intent:

- 直接Intent:指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context, Class)来指定)。通过指定具体的组件类,通知应用启动对应的组件。

- 间接Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在在所有的可用组件中,确定满足此Intent的组件。

对于直接Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些间接Intent,通过解析,将 Intent映射给可以处理此Intent的Activity、IntentReceiver或Service。

Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有<intent-filter>及其中定义的Intent,通过PackageManager(注:PackageManager能够得到当前设备上所安装的application package的信息) 来查找能过处理这个Intent的component。在这个解析过程中,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,解析得到的目标组件必须至少包含这两个类别。


下面,以Android SDK中的便笺例子来说明,Intent如何定义及如何被解析。这个应用可以让用户浏览便笺列表、查看每一个便笺的详细信息。

Manifest.xml

Xml代码
  1. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
  2. package="com.google.android.notepad">
  3. <applicationandroid:icon="@drawable/app_notes"
  4. android:label="@string/app_name">
  5. <providerclass="NotePadProvider"
  6. android:authorities="com.google.provider.NotePad"/>
  7. <activityclass=".NotesList"="@string/title_notes_list">
  8. <intent-filter>
  9. <actionandroid:value="android.intent.action.MAIN"/>
  10. <categoryandroid:value="android.intent.category.LAUNCHER"/>
  11. </intent-filter>
  12. <intent-filter>
  13. <actionandroid:value="android.intent.action.VIEW"/>
  14. <actionandroid:value="android.intent.action.EDIT"/>
  15. <actionandroid:value="android.intent.action.PICK"/>
  16. <categoryandroid:value="android.intent.category.DEFAULT"/>
  17. <typeandroid:value="vnd.android.cursor.dir/vnd.google.note"/>
  18. </intent-filter>
  19. <intent-filter>
  20. <actionandroid:value="android.intent.action.GET_CONTENT"/>
  21. <categoryandroid:value="android.intent.category.DEFAULT"/>
  22. <typeandroid:value="vnd.android.cursor.item/vnd.google.note"/>
  23. </intent-filter>
  24. </activity>
  25. <activityclass=".NoteEditor"="@string/title_note">
  26. <intent-filterandroid:label="@string/resolve_edit">
  27. <actionandroid:value="android.intent.action.VIEW"/>
  28. <actionandroid:value="android.intent.action.EDIT"/>
  29. <categoryandroid:value="android.intent.category.DEFAULT"/>
  30. <typeandroid:value="vnd.android.cursor.item/vnd.google.note"/>
  31. </intent-filter>
  32. <intent-filter>
  33. <actionandroid:value="android.intent.action.INSERT"/>
  34. <categoryandroid:value="android.intent.category.DEFAULT"/>
  35. <typeandroid:value="vnd.android.cursor.dir/vnd.google.note"/>
  36. </intent-filter>
  37. </activity>
  38. <activityclass=".TitleEditor"="@string/title_edit_title"
  39. android:theme="@android:style/Theme.Dialog">
  40. <intent-filterandroid:label="@string/resolve_title">
  41. <actionandroid:value="com.google.android.notepad.action.EDIT_TITLE"/>
  42. <categoryandroid:value="android.intent.category.DEFAULT"/>
  43. <categoryandroid:value="android.intent.category.ALTERNATIVE"/>
  44. <categoryandroid:value="android.intent.category.SELECTED_ALTERNATIVE"/>
  45. <typeandroid:value="vnd.android.cursor.item/vnd.google.note"/>
  46. </intent-filter>
  47. </activity>
  48. </application>
  49. </manifest>



例子中的第一个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的便笺的标题。

***************************************************************************

更多相关文章

  1. android activity之间传值
  2. 安卓基础知识总结
  3. Android(安卓)数据存储五种方式使用与总结
  4. 可靠的功能测试--Espresso和Dagger2
  5. Android使用XML文件定义用户界面
  6. Android(安卓)之 数据存储方式
  7. Android(安卓)串口开发知识总结(未完待续)
  8. Android(安卓)面试题(1)
  9. mybatisplus的坑 insert标签insert into select无参数问题的解决

随机推荐

  1. android 保持屏幕长亮及解锁的方法
  2. android使用Intent操作拨打电话和发送短
  3. Android(安卓)Studio gradle插件版本和gr
  4. EXOPlayer居中播放,类似ImageView的CENTER
  5. android 获取进程名字
  6. android按钮main.xm_基础篇
  7. Android之checkbox使用
  8. test
  9. Android WebView图片显示问题
  10. Android和IOS录制mp3语音文件的方法