Intent组件构成,解析机制

        一个应用中通常包含多个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同时指定为Type为Image,则调出浏览图片的应用).一般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";

	@Override
	public 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 One
				Intent 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。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值