Intent(意图)在Android中是一个十分重要的组件,它是连接不同应用的桥梁和纽带,也是让组件级复用(Activity和 Service)成为可能的一个重要原因。Intent的使用分为二个方面一个是发出Intent,另一个则是接收Intent用官方的说法就是Intent Resolving。本主将对Intent和IntentFilter进行一些介绍。
Android 应用程序中有三大核心组件: Activity, Service, Broadcast Receiver 都是通过被称之为意图的消息运行。Intent messaging is a facility for late run-time binding between components in the same or different applications. 意图本身一个 Intent 对象,它保存了对要执行操作的抽象描述—对于broadcasts来说,则表示对已经发生并且正要报告的操作。对这下三种组件,发送intents分别有不同的机制。
1) 传递一个Intent对象到 Context.startActivity(intent) 或者 Activity.startActivity ForResult(int) 去运行一个Activity(可以在通过此方式启动后的Activity中调用 Activity.setResult() 设置结果参数,该参数将会在启动当前activity的activity中被接收---可以通过onActivityResult(int requestCode, int resultCode, Intent data) 接收)
2) 传递一个Intent对象到 Context.startService(intent) 去启动一个service 或者 传递一个新的指令到正在运行的service中。另外,还可以通过 Context.bindService(intent) 去绑定一个Service。(在调用组件和目标Service 建立一个连接)
3) 传递一个Intent对象到 任何一个broadcast methods (如: Context.sendBroadcast() , Context.sendOrderedBroadcast(), Context.sendStickyBroadcast() ) 该intent将被传递给所有已经被注册的broadcast receiver中。
在以上的三种情况下,当Intent被传递出后,Android系统会找到适合的activity,service,或者是多个broadcast receiver去响应这个intent。,这三种情况不会存在重叠的部分,它们相互独立,互不干扰。
Intent的产生的作用主要有两点:1.提供一致的编程模型,2.实现松散耦合的效果。
Intent消息机制通常有二种,一个是显式Intent(Explicit Intent)用于明确需要跳转的组件,另一个是隐式Intent(Implicit Intent),只提出意图,没有明确跳转的组件。
显式Intent: 需要在Intent中明确指定目标组件,也就是在Intent中明确写明目标组件的名称(Component name),需要指定完整的包名和类名。因为对于本程序以外的其他应用程序,你很难知道它的组件名字,所以显式的Intent通常用于应用程序内部通信,更确切的说,显示Intent是用于应用程序内部启动组件,通常又是Activity或Service。还没有见用显式Intent来给BroadcastReceiver发送广播的。
隐式Intent: 也就是不在Intent中指定目标组件,在Intent中不能含有目标的名字。系统是根据其他的信息,比如Data,Type和Category去寻找目标组件。隐式Intent通常用于与应用程序外部的组件进行通信。应用程序级别的组件复用也主要是靠隐式Intent来完成的。而IntentFilter也是只有隐式Intent才用的着,显式Intent都是直接把Intent传递给目标组件,根本不会理会组件的IntentFilter。
(1)显式Intent
在构造Intent对象时就指定接收者,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的。Intent跳转Activity实现如下:
<span style="white-space:pre"> </span>// 显示Intent
// 通过直接指定组件实现
Intent intent = new Intent();
intent.setClass(this, Activity2.class);
// intent.setComponent(new ComponentName(this, Activity2.class));
// intent.setClassName(this, "com.lingyun.blog.intent.Activity2");
// intent.setClassName("com.lingyun.blog.intent",
// "com.lingyun.blog.intent.Activity2");
startActivity(intent);</span>
Intent可以使用以下几种方法设置Component属性,虽然设置的方法有这么多,但Intent内部标识目标组件的属性只有一个Component,所以这么设置方法的目的也只是设置目标组件的Component,事实上有这么多的方法原因在于ComponentName的构造是多重载了的。在解析Intent时,系统也是取得这个Component属性,然后去启动它。
setComponent(ComponentName component);
setClass(Context packageContext, Class<?> cls);
setClassName (Context packageContext, String className);
setClassName (String packageName, String className);
(2)隐式Intent
隐式的Intent,即Intent的发送者在构造Intent对象时,并不知道也不关心接收者是谁,有利于降低发送者和接收者之间的耦合,它一般用在没有明确指出目标组件名称的前提下,一般是用于在不同应用程序之间。
// 隐式Intent
// 通过Action实现
Intent intent = new Intent();
intent.setAction("com.lingyun.action.HELLO");
intent.addCategory("com.lingyun.category.ABC");
startActivity(intent);
在此之前我们需要在AndroidManifest中对相应Activity进行配置,如下:
<activity android:name=".Activity2" >
<intent-filter>
<action android:name="com.lingyun.action.HELLO" />
<category android:name="com.lingyun.category.ABC" />
<!-- 注意:需要将下面的category一同加入 -->
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
隐式Intent常用于不同应用之间,可以使用Intent调用系统拨打电话、发短信等功能,如下:
// 隐式Action调用其他应用
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
//打电话
//intent.setData(Uri.parse("tel://110"));
//打开网页
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
// 发短信
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("smsto:10086"));
intent.putExtra("sms_body", "hello 10086");
startActivity(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属性
一个Intent对象是一个信息包。它包含了要接收此Intent的组件需要的信息(例如需要的动作和动作需要的信息)和 android 系统需要的信息(要处理此Intent的组件的类别和怎样启动它)
总的来说,Intent Object 主要包括以下信息:
Ø 动作(Action)
一个字符串,代表要执行的动作。系统中给出了很多Action,包括目标组件是Activity或者广播的,用户也可以定义自己的 action strings 来激活组件。自定义的action 应该包含包名作为前缀: 例如"com.example.project.MYACTION".
Constent( 常量) | Target Component (目标组件) | Action (动作 ) |
ACTION_CALL | activity | 初始化一个电话呼叫 |
ACTION_EDIT | activity | 显示用户要编辑的数据 |
ACTION_MAIN | activity | 将该Activity作为task的第一个Activity ,没有数据输入,也没有数据返回 |
ACTION_SYNC | activity | 在设备上同步服务器上的数据 |
ACTION_BATTERY_LOW | broadcast receiver | 电量不足的警告 |
ACTION_HEADSET_PLUG | broadcast receiver | 耳机插入设备,或者从设备中拔出 |
ACTION_SCREEN_ON | Broadcast receiver | 屏幕已经点亮 |
ACTION_TIMEZONE_CHANGED | Broadcast receiver | 时区设置改变 |
Ø Data
Data属性有两部分构成: 数据URI 和 数据MIME type 。 action的定义往往决定了data该如何定义。 例如: 如果 一个Intent的 action 为 ACTION_EDIT 那么它对应的data 应该包含待编辑的数据的URI . 如果一个action 为:ACTION_CALL ,那么data 应该为 tel: 电话号码的URI . 类似的, 如果action 为 ACTION_VIEW 那么data 应该为: http: URI , 接收到的activity 将会下载并显示相应的数据。
当一个Intent 和 有能力处理此Intent的组件进行匹配时, 除了 data的URI以外,了解data的类型(MIME Type)也很重要。 例如: 一个显示图片的组件 不应该去播放声音文件。
许多情况下,data type 可以从URI中推测出。 尤其是: URI = content: URIs这时候数据通常是位于本设备上而且是由某个content provider来控制的。即便如此,我们仍然可以明确的在 Intent object上设置一个 data type。 setData() 方法只能设置URI, setType() 设置MIME type, setDataAndType() 可以对二者都进行设置, 获取URI 和 data type 可分别调用 getData() 和 getType() 方法。
Ø Category
包含了处理该Intent的组件的种类信息, 起着对action的补充说明作用.一个Intent对象可以有任意多个 category。和action 一样, 在Intent class 中也定义了几个 category 常量。
Constant | Meaning |
CATEGORY_BROWSABLE | 目标Activity可以使用浏览器显示数据 |
CATEGORY_GADGET | 该activity可以被包含在另外一个装载小工具的activity中. |
CATEGORY_HOME | 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. |
CATEGORY_LAUNCHER | The activity can be the initial activity of a task and is listed in the top-level application launcher. 可以让一个activity出现在launcher |
CATEGORY_PREFERENCE | The target activity is a preference panel. 该activity是一个选项面板 |
Ø Extras
为键-值对形式的附加信息. 例如ACTION_TIMEZONE_CHANGED的intent有一个"time-zone"附加信息来指明新的时区, 而ACTION_HEADSET_PLUG有一个"state"附加信息来指示耳机是被插入还是被拔出.
intent对象有一系列put...()和set...()方法来设定和获取附加信息. 这些方法和Bundle对象很像. 事实上附加信息可以使用putExtras()和getExtras()作为Bundle来读和写.
Ø Flags
有各种各样的标志,许多指示Android系统如何去启动一个活动(例如,活动应该属于那个任务)和启动之后如何对待它(例如,它是否属于最近的活动列表)。所有这些标志都定义在Intent类中。