我们最常使用Intent来实现Activity之间的转跳,最近做一个app用到从系统搜索图片的功能,使用到了intent的 setType 方法和 setAction 方法,网上搜索一番,发现实现转跳只是Intent功能的九牛一毛,现在对Intent功能做一个总结,以作备忘。
我们经常使用如下方法实现一个转跳:
Intent intent = new Inent(MainActivity.this,SecondActivity.class); startActivity(intent);
其实这种写法还可以写作
Intent intent = new Intent(); intent.setClass(MainActivity.this,SecondActivity.class); startActivity(intent);
这种启动方式被称之为“显式意图”,因为它直接指定了意图目标
还有一种方式称之为“隐式意图”,我们不直接指定目标组件,而是通过设置Intent的各个属性来启动目标组件
Intent
Intent由 ComponentName 、 Action 、 Data 、 Category 、 Extra 、 Flag 六部分来组成,Intent通过调用 setXXX() 方法来设置其对应的属性,下面详细介绍各个属性
【ComponentName】
ComponentName 用于标识位移的应用程序组件,即指明了期望的Intent,这种对象的名称是由目标组件的包名,与期望的类名组合而成,在Intent传递过程中,组件名称是一个可选项。当指定它时,便是显式的Intent消息;而当不指定它时,Android系统会根据其他信息,以及IntentFilter的过滤条件来选择相应的组件。
【Action】
Action 实际上就是一个描述了Intent所出发动作名称的字符串,在Intent类中,已经定义好很多字符串常量来表示不同的Action,当然开发人员也可以自定义Action
常见的Action常量
ACTION_CALL——播出Data里封装的电话号码
ACTION_EDIT——打开Data里指定数据所对应的编辑程序
ACTION_VIEW——打开能够显示Data之中封装的数据的应用程序
ACTION_MAIN——声明程序入口,该Activity并不会接收任何数据,同时结束后也部会返回任何数据
ACTION_BOOT_COMPLETED——BraodcastReceiver Action常量,表明系统启动完毕
ACTION_TIME_CHANGED——BraodcastReceiver Action常量,表示系统时间通过设置而改变
更多可以查看 http://www.cnblogs.com/xs104/p/5111858.html
因为API的更新,部分名称会改变,但基本思路不变。
【Data】
Data 主要是对Intent消息中数据的封装,主要描述Intent的动作所操作到底数据的URI及类型。不同类型的 Action会有不同的Data封装,例如打电话的Intent会封装tel://格式的电话URI,而ACTION_VIEW的Intent中Data则会封装http://格式的URI,正确的Data封装对Intent匹配请求同样非常重要
【Category】
Category 是对目标组件类别信息的描述,同样为一个字符串对象,一个Intent中可以包含多个Category,与Category相关的方法有三个:
1.添加一个Category——addCategory
2.删除一个Category——removeCategory
3.得到一个Category——getCategory
Android系统同样定义了一组常量来表示Intent的不同类别,一些常见的Category常量
CATEGORY_GADGET,表示目标Activity是可以嵌入到其他Activity中的。
CATEGORY_HOME,表明目标Activity为HOME Activity。
CATEGORY_TAB,表明目标Activity是TabActivity的一个标签下的Activity。
CATEGORY_LAUNCHER,表明目标Activity是应用程序中最先被执行的Activity。
CATEGORY_PREFERNCE,表明目标Activity是一个偏好设置的Activity。
【Extra】
extra 中封装了一些额外附加的信息,这些信息以键值对的形式存在,Intent可以通过putExtras()和getExtras()方法来存储和获取Extra,Android系统同样定义了一些Extra常量
EXTRA_CC,邮件抄送人邮箱地址。
EXTRA_EMAIL,装有邮件发送地址的字符串数组。
EXTRA_SUBJECT,当使用ACTION_SEND动作时,描述要发送邮件的主题。
EXTRA_TEXT,当使用ACTION_SEND动作时,描述要发送文本的信息。
【Flags】
android中Intent的Flags有20多种,如下
FLAG_GRANT_READ_URI_PERMISSION FLAG_GRANT_WRITE_URI_PERMISSION FLAG_DEBUG_LOG_RESOLUTION FLAG_FROM_BACKGROUND FLAG_ACTIVITY_BROUGHT_TO_FRONT FLAG_ACTIVITY_CLEAR_TASK FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS FLAG_ACTIVITY_FORWARD_RESULT FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY FLAG_ACTIVITY_MULTIPLE_TASK FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NO_ANIMATION FLAG_ACTIVITY_NO_HISTORY FLAG_ACTIVITY_NO_USER_ACTION FLAG_ACTIVITY_PREVIOUS_IS_TOP FLAG_ACTIVITY_RESET_TASK_IF_NEEDED FLAG_ACTIVITY_REORDER_TO_FRONT FLAG_ACTIVITY_SINGLE_TOP FLAG_ACTIVITY_TASK_ON_HOME FLAG_RECEIVER_REGISTERED_ONLY
但是我们常用的只有4种
FLAG_ACTIVITY_CLEAR_TOP 例如现在的栈情况为:A B C D 。D此时通过intent跳转到B,如果这个intent添加FLAG_ACTIVITY_CLEAR_TOP 标记,则栈情况变为:A B。如果没有添加这个标记,则栈情况将会变成:A B C D B。也就是说,如果添加了FLAG_ACTIVITY_CLEAR_TOP 标记,并且目标Activity在栈中已经存在,则将会把位于该目标activity之上的activity从栈中弹出销毁。这跟上面把B的Launch mode设置成singleTask类似。
FLAG_ACTIVITY_NO_HISTORY例如现在栈情况为:A B C。C通过intent跳转到D,这个intent添加FLAG_ACTIVITY_NO_HISTORY标志,则此时界面显示D的内容,如果此时D中又跳转到E,栈的情况变为:A B C E,此时按返回键会回到C,因为D根本就没有被压入栈中。
FLAG_ACTIVITY_SINGLE_TOP和上面Activity的 Launch mode的singleTop类似。如果某个intent添加了这个标志,并且这个intent的目标activity就是栈顶的activity,那么 将不会新建一个实例压入栈中。
FLAG_ACTIVITY_NEW_TASK例如现在栈1的情况是:A B C。C通过intent跳转到D,并且这个intent添加了FLAG_ACTIVITY_NEW_TASK 标 记,如果D这个Activity在Manifest.xml中的声明中添加了Task affinity,并且和栈1的affinity不同,系统首先会查找有没有和D的Task affinity相同的task栈存在,如果有存在,将D压入那个栈,如果不存在则会新建一个D的affinity的栈将其压入。如果D的Task affinity默认没有设置,或者和栈1的affinity相同,则会把其压入栈1,变成:A B C D,这样就和不加FLAG_ACTIVITY_NEW_TASK 标记效果是一样的了。
注意如果试图从非activity的非正常途径启动一个activity,比如从一个service中启动一个activity,则intent必须要添加 FLAG_ACTIVITY_NEW_TASK 标记。
更多:Intent中的Flag
IntenFilter
IntentFilter 描述了一个组件愿意接收什么样的Intent对象,Android将其抽象为android.content.IntentFilter类。在 Android 的AndroidManifest.xml 配置文件中可以通过 <intent-filter> 节点,为一个Activity指定其IntentFilter,以便告诉系统该Activity可以响应什么类型的 Intent。这样的Intent称为隐式的Intent。
当程序员使用startActivity(intent)来启动另外一个Activity时,如果直接指定intent了对象的Component属性,那么Activity Manager将试图启动其Component属性指定的Activity。否则Android将通过Intent的其它属性,从安装在系统中的所有Activity中查找与之最匹配的一个启动。如果没有找到合适的Activity,应用程序会得到一个系统抛出的异常。
Intent的匹配
Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的Intent,最终找到匹配的Intent。在这个解析过程中,Android是通过Intent的action、type、category这三个属性来进行判断的,判断方法如下:
1 如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配;
2 如果Intent没有提供type,系统将从data中得到数据类型。和action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。
3 如果Intent中的数据不是content: 类型的URI,而且Intent也没有明确指定它的type,将根据Intent中数据的scheme (比如 http: 或者mailto:) 进行匹配。
同上,Intent 的scheme必须出现在目标组件的scheme列表中。
4 如果Intent指定了一个或多个category,这些类别必须全部出现在组建的类别列表中。
比如Intent中包含了两个类别:LAUNCHER_CATEGORY 和 ALTERNATIVE_CATEGORY,解析得到的目标组件必须至少包含这两个类别。每一个通过startActivity()方法发出的隐式Intent都至少有一个category,就是"android.intent.category.DEFAULT",
所以只要是想接收一个隐式Intent的Activity都应该包括"android.intent.category.DEFAULT" category,不然将导致 Intent 匹配失败。