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 ,向作者表示感谢

posted @ 2014-11-09 19:43  RoperLee  阅读(217)  评论(0)    收藏  举报