本文主要介绍Intent和Intent Filter的概念及作用、Intent的结构、两种类型Intent、 Intent和Intent Filter 的匹配规则、利用Intent调用其他常见程序。
1、Intent和Intent Filter的介绍及作用
Android包含四大组件Activity、Service、Broadcast Receiver、Content Provider。其中的Activity、Service、Broadcast Receiver之间如何进行通信,如当前处在Activity A,如何切换到ActivityB,如何启动一个Service,如何注册一个Broadcast,如何发送一条短信,如何打开本机的地图或是浏览器呢,这些都要用到Intent。
Intent是抽象的数据结构,包含了一系列描述某个操作的数据,使得程序在运行时可以在程序中不同组件间通信或启动不同的应用程序。可以通过startActivity(Intent)
启动一个Activity, sendBroadcast(Intent) 发送广播发送给感兴趣的BroadcastReceiver组件, startService(Intent)启动service,bindService(Intent, ServiceConnection, int)绑定服务。
Intent Filter顾名思义就是Intent的过滤器,组件通过定义Intent Filter可以决定哪些隐式Intent可以和该组件进行通讯。关于隐式Intent的定义后面会进行介绍,Intent Filter对显式的Intent不起作用。
2、Intent结构
Intent结构如下
private String mAction; private Uri mData; private String mType; private String mPackage; private ComponentName mComponent; private int mFlags; private HashSet<String> mCategories; private Bundle mExtras; private Rect mSourceBounds;
Intent的主要成员是mAction和mData
Action就是个String类型的字符串,在隐式Intent中用来和filter进行匹配的关键指标,如ACTION_VIEW,ACTION_EDIT等,Intent内置了很多Action常量,我们也可以自定义私有Action方便自己进行匹配。
Data为Uri类型的数据,若mType为空通过对mData的解析可以得到数据的类型。
Component表示组件信息,包含context和目标组件的class信息,设置了即为显示Intent。
Category作为决定哪个组件处理Intent的附属信息,一个Intent可以添加或删除多个Category存储在mCategories。
Flag用于标记如何启动一个活动,是NEW_TASK还是其他等等,以及启动后怎么对待这个活动。
Extras为附加信息,会传递给目标组件,比如发送邮件,Extras可以存储邮件收件人地址、内容、主题、附件等信息。
因为Intent Filter和Intent的匹配只有三个字段起作用,所以Intent Filter只包含Actions、Datas、Categorys三个属性(实际源码中会将Data划分为多个部分),属性的意义和Intent相同。不同的是Intent Filter可以包含多个Action、多个Data、多个Category,而Intent除Category可以有多个外,只能有一个Action、一个Data。
3、两种类型的Intent
对于一个定义好的Intent,Android如何判断和哪个目标组件通讯呢。Intent分为隐式(implicit)Intent和显式(explicit)Intent。
显式Intent通常用于在程序内部组件间通信,已经明确的定义目标组件的信息,所以不需要系统决策哪个目标组件处理Intent,如下
Intent intent = new Intent(DemoList.this, GoogleMapDemo.class); startActivity(intent);
其中DemoList和GoogleMapDemo都是用户自定义的组件,
隐式Intent不指明目标组件的class,只定义希望的Action及Data等相关信息,由系统决定使用哪个目标组件。如发送短信
Uri uri = Uri.parse("smsto:15800000000"); Intent i = new Intent(Intent.ACTION_SENDTO, uri); i.putExtra("sms_body", "The SMS text"); startActivity(i);
这也是Android系统设计的一个亮点之一,通过隐式的Intent可以方便的调用其他程序的组件,比如调用地图、短息、打电话、拍照组件为自己的程序所用。这里就涉及下一个问题,系统如何决定目标组件呢?
4、Intent和<intent-filter>的匹配规则
Android系统通过对Intent和目标组件在AndroidManifest文件中定义的<intent-filter>(也可以在程序中定义Intent Filter)进行匹配决定和哪个目标组件通讯。如果某组件未定义<intent-filter>则只能通过显式的Intent进行通信。Intent的三个属性用于对目标组件选取的决策,分别是Action、Data(Uri和Data Type)、Category。匹配规则如下
a. Intent定义的Action必须包含在<intent-filter>的Action列表中,若隐式Intent未定义Action系统会报错。由此可知一个<intent-filter>至少包含一个Action。
b. 未定义Uri和Type的Intent仅可以通过不包含包含Uri和Type的filter;包含了Uri,不包含Type的Intent仅可以通过包含匹配Uri不包含Type的filter;包含了Type不包含Uri的Intent仅可以通过包含了相同Type不包含Uri的filter;同时包含了Uri和Type的Intent仅可以通过相同Type匹配Uri(或不包含Uri但Intent Uri为content:或file:)的filter。
c. Intent若定义了Category(可多个),则所有Category必需包含在<intent-filter>的Category列表中。若Intent未定义Category,则<intent-filter>是否定义Category不影响。
PS:<intent-filter>必须包含<category android:name="android.intent.category.DEFAULT" />才能通过startActivity启动,所以Activity的<intent-filter>至少包含一个category,Service和BroadcastReceiver不必。
目标组件必须包含同时满足以上规则的<intent-filter>才能进行匹配。若有多个目标组件同时可以匹配,则系统会提示用户进行选择,若没有目标组件可以匹配系统会进行提示。
如某组件filter如下
<intent-filter android:label="@string/resolve_edit"> <action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.EDIT" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.item/vnd.google.note" /> </intent-filter>
则{action=android.intent.action.INSERT}不可以通过
{action=android.intent.action.VIEW category=android.intent.category.ALTERNATIVE}不可以通过
{action=android.intent.action.VIEW data=content://com.google.provider.NotePad/notes/{ID}}可以通过
{action=android.intent.action.VIEW data=smsto:15800000000}不可以通过
5、利用Intent调用其他常见程序
a. 发送短信
Uri uri = Uri.parse("smsto:15800000000"); Intent i = new Intent(Intent.ACTION_SENDTO, uri); i.putExtra("sms_body", "The SMS text"); startActivity(i);
b. 打电话
Uri dial = Uri.parse("tel:15800000000"); Intent i = new Intent(Intent.ACTION_DIAL, dial); startActivity(i);
c. 发送邮件
Uri email = Uri.parse("mailto:abc@126.com;def@126.com"); Intent i = new Intent(Intent.ACTION_SENDTO, email); startActivity(i);
或
Intent i = new Intent(Intent.ACTION_SEND); String[] tos = {"abc@126.com"}; String[] ccs = {"def@126.com"}; i.putExtra(Intent.EXTRA_EMAIL, tos); i.putExtra(Intent.EXTRA_CC, ccs); i.putExtra(Intent.EXTRA_SUBJECT, "主题"); i.putExtra(Intent.EXTRA_TEXT, "正文"); i.setType("message/rfc822"); startActivity(i);
d. 拍照
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); String folderPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "AndroidDemo" + File.separator; String filePath = folderPath + System.currentTimeMillis() + ".jpg"; new File(folderPath).mkdirs(); File camerFile = new File(filePath); i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(camerFile)); startActivityForResult(i, 1);
e. 浏览网页
Uri web = Uri.parse("http://www.google.com"); Intent i = new Intent(Intent.ACTION_VIEW, web); startActivity(i);
f. 查看联系人
Intent i = new Intent(); i.setAction(Intent.ACTION_GET_CONTENT); i.setType("vnd.android.cursor.item/phone"); startActivityForResult(i, 1);
其他更多可以见http://www.apkbus.com/forum.php?mod=viewthread&tid=13667&extra=page%3D3%26orderby%3Dlastpost
参考:
http://developers.androidcn.com/reference/android/content/Intent.html
http://developer.android.com/guide/components/intents-filters.html