Android Intent的详细剖析
一、什么是Intent
1、Intent的概念:
- Android中提供了Intent机制来协助应用间的交互与通讯,或者采用更准确的说法是,Intent不仅可用于应用程序之间,也可用于应用程序内部的activity, service和broadcast receiver之间的交互。Intent这个英语单词的本意是“目的、意向、意图”。
- Intent是一种运行时绑定(runtime binding)机制,它能在程序运行的过程中连接两个不同的组件。通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件来响应。
activity、service和broadcast receiver之间是通过Intent进行通信的,而另外一个组件Content Provider本身就是一种通信机制,不需要通过Intent。我们来看下面这个图就知道了:

2、对于向这三种组件发送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。
二、Intent的相关属性:
- Intent由以下各个组成部分:
- component(组件):目的组件
- action(动作):用来表现意图的行动
- category(类别):用来表现动作的类别
- data(数据):表示与动作要操纵的数据
- type(数据类型):对于data范例的描写
- extras(扩展信息):扩展信息
- Flags(标志位):期望这个意图的运行模式
Intent类型分为显式Intent(直接类型)、隐式Intent(间接类型)。官方建议使用隐式Intent。上述属性中,component属性为直接类型,其他均为间接类型。
相比与显式Intent,隐式Intnet则含蓄了许多,它并不明确指出我们想要启动哪一个活动,而是指定一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动。需要非常注意的一点是:对于隐式Intent意图而言,即,action、category、data、type这几个属性,他们是一种层层细化的关系,也就是说,对于一个Activity和Intent而言,我们都是先从action开始配置和设置,只有上层的属性指定了,才会使用下层的属性,议案不会也不能越级配置和设置这些属性,那样往往会出问题,同时也违反了Intent的隐式意图的用意,他们使用一种逐步细化的关系,使用的属性越多,表明一个Intent的意图或者一个Activity能够被启动的意图越明显
1、显式Intent——component
即通过component直接指定需要启动的组件
public class Activity_Intent extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity__intent); Button bt = (Button) findViewById(R.id.button); bt.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { ComponentName comp = new ComponentName(Activity_Intent.this, ThirdActivity.class); Intent intent = new Intent(); intent.setComponent(comp); startActivity(intent); } }); }
}
此外显示的Intent的方法还有:
①ComponentName的构造器
ComponentName(String pkg , String cls);
ComponentName(Context pkg , String cls);
ComponentName(Context pkg, Class<?> cls) ;
②先构建一个空Intent实例(Intent intent = new Intent() ;),之后在调用Intent的下列方法:
setClass(Context packageContext , Class<?> cls)
setClass(Context packageContext , String className)
setClass(String packageName , String className)
③直接通过Intent的构造方法直接构造:
Intent(Context packageContext , Class<?> cls)
2、隐式Intent——Action和Category
① 注意,如果要使用隐式的Intent的话,那么在使用<intent-filter...../>为Activity或者Service、BroadcastReceive进行配置时,至少要有下面的这一行
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
因为只要使用隐式的Intent启动的话,那么虽然不为Intent设置"android.intent.category.DEFAULT"这个category,程序也会默认的添加这个category,
②一般来说,Action和category在一起使用,Action表示一种动作,Category代表一种附加的额外信息
③一个Activity或者其他组件可以通过<intent-filter>配置多个<action/><category/>属性,表示这个组件能够响应多种Intent请求,
但是一个Intent只能够通过setAction(String str)方法设置一种Action,但是可以通过addCategory(String str)设置多种Category
④虽然Action和Category都是一个任意设定的字符串,但是我们还是要规范一下,最好在设置Action、Category字符串时在加上 "action.XXX" 和"category.XXX"前缀,
XXX一般使用全大写,最好能够表明这个Action或者Category是哪种响应,如:“action.URL_VIEW_ACTION” , 表明这个组件能够响应URL浏览请求
举例:
public class Activity_Intent extends Activity { //定义一个Action常量 final static String TEXT_ACTION ="action.TEXT_ACTION" ; //定义一个Category常量 final static String TEXT_CATEGORY="category.TEXT_CATEGORY"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity__intent); Button bt = (Button) findViewById(R.id.button); bt.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(Activity_Intent.TEXT_ACTION); intent.addCategory(Activity_Intent.TEXT_CATEGORY); startActivity(intent); } }); } }
Mainfest.xml配置文件中SecondActivity的配置为:
<activity> android:name="com.penglee.test_intent2.SecondActivity"> <intent-filter> <action android:name="action.TEXT_ACTION"/> <category android:name="category.TEXT_CATEGORY" /> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>
注意,不要丢了<category android:name="android.intent.category.DEFAULT"/>这一行
3、隐式Intent——Data和Type
首先先从Intent这个方面来做一下讲解,之后再从组件的属性配置方面说明一下
①为Intent设置Data属性的时候,首先需要定义一个Uri实例对象,之后调用Intent的setData(Uri data) ; 将创建的Uri对象封装到Intent实例中
②为Intent设置Type属性的时候,调用Intent的setType(String type)方法即可,也就是说,Type属性实际上就是一个String字符串
③需要注意的是:
如果为Intent先设置Data属性,后设置Type属性,那么Type属性将会覆盖Data属性,也就是说Data属性将不会起作用
如果为Intent先设置Type属性,后设置Data属性,那么Data属性将会覆盖Type属性,也就是说Type属性将不会起作用
如果想要让Data和Type属性同时起作用的话,要调用Intent的setDataAndType(Uri data , String type);方法
如何在Manifest.xml文件中为组件配置Data和Type属性
在为组件配置Data和Type属性的时候,都通过<data.../>元素来声明,格式如下:
<intent-filter>
<data
android:scheme="...." 用于声明该组件能匹配的Intent的Data属性的scheme属性
android:host="...."
android:port="...."
android:path="...."
android:mimeType="...." 用于声明该组件能匹配的Intent的Type属性
/>
</intent-filter>
注意这样的一个问题:Data属性和Type属性是配合使用的,他们之间不仅有上面的覆盖规则,还有下面的相互约束:
①当Activity等组件中并没有定义Type属性的时候,那么Data的匹配过程如下:
如果目标组件的<data>子元素中只指定了android:scheme属性,那么只要Intent的Data属性的scheme部分与android:scheme属性相同,即可启动该组件
如果目标组件的<data>子元素中只指定了android:scheme和android:host属性,那么只要Intent的Data属性的scheme、host部分与android:scheme、android:host属性相同,即可启动该组件
如果目标组件的<data>子元素中只指定了android:scheme和android:host和android:port属性,那么只要Intent的Data属性的scheme、host、port部分与android:scheme、android:host、android:port属性相同,即可启动该组件
如果目标组件的<data>子元素中只指定了android:scheme和android:host和android:port和android:path属性,那么只要Intent的Data属性的scheme、host、port、path部分与android:scheme、android:host、android:port、android:path属性相同,即可启动该组件
②如果Activity等组件中定义了Type属性的话,那么:
Intent的Data部分的匹配规则和上面一样,但是Intent中必须有Type属性的设置,且Type属性还要和组件定义的Type属性一致才能够启动这个组件,如果Intent中只是设定了Data属性,那么无论如何也不能够启动声明了Type的组件
4、Extra属性
这个属性在显示的Intent和隐式的Intent中都能够使用,它就是前面讲的用来在各个组件之间来传递数据的,设置这个属性就是调用Intent的
putExtra(Bundle data)
Bundle getExtra()
putExtra(String name , Xxx value)
getXxxExtra(String name)
在之前已经介绍过了,就不在多说了
5、Flag属性
这个属性也非常的重要,Flag成为Intent的控制标旗,调用Intent的addFlag()方法来为Intent添加Flag标旗,这个标旗将会控制组件的启动方式:
①FLAG_ACTIVITY_BROUGHT_TO_FRONT:如果通过该Flag启动的Activity已经存在,下次再启动时,将只是将Activity带到前台。例如现在Activity栈中有Activity A ,此时以该标旗启动B,然后在 B 中启动 C D , 如果此时在 D中再启动 B , 将直接把Activity栈中的B 带到前台,此时的栈中情形是:ACBD
②FLAG_ACTIVITY_CLEAR_TOP:这个标旗相当于加载singleTask ,通过这种方式启动的activity将会把要启动的Activity之上的Activity全部弹出栈,例如:栈中有ABCD,如果采用这个标旗从Activity D中启动B,那么栈中将只包含 AB
③FLAG_ACTIVITY_NEW_TASK:默认的启动标旗,该标旗将会重新创建一个新的Activity
④FLAG_ACTIVITY_NO_ANIMATION:该标旗控制启动AcTIVITY 的时候将不会使用过渡动画
⑤FLAG_ACTIVITY_NO_HISTORY:该标旗控制被启动的Activity将不会留在栈中,例如:栈中原来有ABC,此时C以该FLAG启动D ,D再启动E,此时栈中只有ABCE
⑥FLAG_ACTIVITY_REORDER_TOFRONT:该标旗控制如果当前已有该Activity ,直接将该Activity带到前台。例如现在栈中有ABCD,如果使用该标签启动B,那么启动后栈中情形为:ACDB
⑦FLAG_ACTIVITY_SINGLE_TOP:该Flag相当于启动模式singleTop,例如原来栈中有ABCD,D再次启动D,则栈中依然是ABCD
当然Intent还有非常多的标旗,就不在一一讲述,可以查阅官方文档
前面部分内容来自:http://www.cnblogs.com/smyhvae/p/3959204.html ,向作者表示感谢

浙公网安备 33010602011771号