一个应用中通常包含多个Activity,Intent在Android中承担着一种指令的传输的作用,就好比人身的神经系统。

Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。

由于Intent的出现,组件只需要将自己的功能通过Intent描述,而不必具体实现对组件的引用,Service、BroadcastReceiver等都是通过Intent组件关联起来的,这些工作全部由Andorid Runtime来实现,因此,Intent最大的优点就是完美地实现了调用者与被调用者之间的解耦。

比如说调用startActivity()来启动一个activity,或者由broadcaseIntent()来传递给所有感兴趣的BroadcaseReceiver,再或者由startService()/bindservice()来启动一个后台的service.所以可以看出来,intent主要是用来启动其他的activity或者service,所以可以将intent理解成activity之间的粘合剂。

二、Intent的构成

在Android参考文档中,对Intent的定义是执行某操作的一个抽象描述(确实很抽象)。我们先来看看这里的抽象描述,到底描述了什么。
首先,是要执行的动作(action)的一个简要描述,如VIEW_ACTION(查看)、EDIT_ACTION(修改)等,Android为我们定义了一套标准动作:(具体的可以查阅android SDK-> reference中的Android.content.intent类,里面的constants中定义了所有的action

标准的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已经从系统中移除

此外,我们还可以根据应用的需要,定义我们自己的动作,并可定义相应的Activity来处理我们的自定义动作。

其次,是执行动作要操作的数据(data),Android中 采用指向数据的一个URI来表示,如在联系人应用中,一个指向某联系人的URI可能为:content://contacts/1。这种URI表示,通过 ContentURI这个类来描述,具体可以参考android.net.ContentURI类的文档。
以联系人应用为例,以下是一些action / data对,及其它们要表达的意图:

  • VIEW_ACTION content://contacts/1-- 显示标识符为"1"的联系人的详细信息
  • EDIT_ACTION content://contacts/1-- 编辑标识符为"1"的联系人的详细信息
  • VIEW_ACTION content://contacts/-- 显示所有联系人的列表
  • PICK_ACTION content://contacts/-- 显示所有联系人的列表,并且允许用户在列表中选择一个联系人,然后把这个联系人返回给父activity。例如:电子邮件客户端可以使用这个Intent,要求用户在联系人列表中选择一个联系人


另外,除了action和data这两个重要属性外,还有一些附加属性:

  • category(类别、范畴),被执行动作的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者应该在Launcher中作为顶级应用出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个,这 些动作可以在同一块数据上执行。
  • type(数据类型)用于指定类型,以供过滤(比如ACTION_VIEW同时指定为TypeImage,则调出浏览图片的应用).一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行判定。
  • component(组件),指定Intent的的目标组件的类名称。通常Android会根据Intent 中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。
  • extras(附加信息),是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。


总之,action、data/type、category和extras 一起形成了一种语言。这种语言使系统能够理解诸如“查看某联系人的详细信息”之类的短语。随着应用不断的加入到系统中,它们可以添加新的action、 data/type、category来扩展这种语言。应用也可以提供自己的Activity来处理已经存在的这样的“短语”,从而改变这些“短语”的行 为。

三、Android如何解析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中的所有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,解析得到的目标组件必须至少包含这两个类别。
  • 例子:

xml文件:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="fill_parent"android:layout_height="fill_parent"><Button android:text="activity1" android:id="@+id/activity1"android:layout_width="wrap_content" android:layout_height="wrap_content"></Button><Button android:text="activity2" android:id="@+id/activity2"android:layout_width="wrap_content" android:layout_height="wrap_content"></Button><Button android:text="service1" android:id="@+id/service1"android:layout_width="wrap_content" android:layout_height="wrap_content"></Button><Button android:text="service2" android:id="@+id/service2"android:layout_width="wrap_content" android:layout_height="wrap_content"></Button></LinearLayout>


Activity文件:

package com.demo.intent;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.widget.Button;public class main extends Activity {public static final String User_ACTION = "com.demo.intent.Useraction";public static final String User_ACTION2 = "com.demo.intent.Useraction2";@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);Button firstbtn = (Button) findViewById(R.id.activity1);Button firstbtnservice = (Button) findViewById(R.id.service1);Button secondbtn = (Button) findViewById(R.id.activity2);Button secondbtnservice = (Button) findViewById(R.id.service2);firstbtn.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {// 显式启动 Activity OneIntent i = new Intent(getApplicationContext(),ActivityOne.class);startActivity(i);}});firstbtnservice.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {Intent i = new Intent(getApplicationContext(), ServiceOne.class);startService(i);}});//隐式启动secondbtn.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {Intent intent = new Intent(); intent.setAction(User_ACTION);startActivity(intent);}});secondbtnservice.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {Intent intent = new Intent();intent.setAction(User_ACTION2);startService(intent);}});}}


应用程序的配置文件AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.demo.intent" android:versionCode="1" android:versionName="1.0"><application android:icon="@drawable/icon" android:label="@string/app_name"><activity android:name="main" android:label="@string/app_name"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity android:name=".ActivityOne" android:label="@string/app_name"></activity><activity android:name=".ActivityTwo" android:label="@string/app_name"><intent-filter><action android:name="com.demo.intent.Useraction" /> <category android:name="android.intent.category.DEFAULT" /></intent-filter></activity><service android:name=".ServiceOne"></service><service android:name=".ServiceTwo"><intent-filter><action android:name="com.demo.intent.Useraction2" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></service></application><uses-sdk android:minSdkVersion="9" /></manifest> 


上面分别演示了显式和隐式启动组件,在显示启动的组件操作中,首先利用组件的类名作为参数来创建Intent对象,然后将此Intent对象作为参数传递给startActivity()或startService()方法,

在隐式启动组件中,首先利用new intent()创建一个空的Intent对象,然后通过setAction,setDateType等方法来设置Intent对象的属性,随后将此Intent对象作为参数传递给startActivity或者startService方法。

如果用过Intent实现调用组件,各组件必须在AndroidManifest.xml中进行配置,并通过Intent-Filter来声明自己的能力,如果不声明Intent-Filter,则组件只能通过显式配置。

对于隐式调用,Intent默认的category为android:intent.category.DEFAULT,如果将<intent-filter>节点的category属相删除,启动程序会抛出异常,显式:ActicityNotFoundException。

所以,对于组件来说,除非不希望被隐式调用,否则一定要加上category属性:android.intent.category.DEFALUT。

更多相关文章

  1. 深入剖析Android四大组件(三)——AIDL实现Android IPC
  2. 打造android ORM框架opendroid(七)——数据库升级方案
  3. android——桌面组件的开发
  4. Android数据通信--USB通信的几种方式及使用场景
  5. Android 使用Sharedpreference存储数据
  6. 使用wireshark 动态显示Android应用中的联网数据
  7. 像网易,新浪新闻android客户端的数据是怎么更新的?
  8. 傻瓜式建立数据库,高效数据库操作代码的编写--android

随机推荐

  1. mysql如何优化插入记录速度
  2. SQL Server实现显示每个类别最新更新数据
  3. SQL Server代理服务无法启动怎么办
  4. SQL服务器无法启动的解决方法
  5. SQL2008的sa账户被禁用其他账户无法连接
  6. MSSQLSERVER不同版本设置开启远程连接(sa
  7. SQL Agent服务无法启动的解决方法
  8. SQL Server 2008 R2登录失败的解决方法
  9. SQL SERVER 2012新增函数之逻辑函数IIF
  10. SQL SERVER 2012新增函数之字符串函数FOR