Android 应用的交互------Intent
为了让用户能够从一个activity跳到另一个activity,我们的app必须使用Intent来定义自己的意图。当使用startActivity()的方法,且参数是intent时,系统会使用这个 Intent 来定义并启动合适的app组件。使用intents甚至还可以让app启动另一个app里面的activity。
Activity、Service和BroadcastReceiver,都是通过Intent机制激活的,而不同类型的组件在传递Intent时有不同的方式。
一.Intent的组成部分
- Component属性需要接受一个ComponentName对象,ComponentName需要指定包名和类名,这就可唯一确定一个组件类,这样应用程序即可根据给定的组件去启动特定的组件。
- Action属性和Category属性都是一个普通的字符串,其中Action代表该Intent所要完成的一个抽象“动作”,而Category则用于为Action增加额外的附加类别信息。通常Action属性会与Category属性结合使用。
- Data属性通常用于向Action属性提供操作的数据。Data属性接受一个Uri对象,Uri字符串总满足如下格式:scheme://host:port/path
- Type属性用于指定该Data所指定Uri对应的MIME类型,这种MIME类型可以是任何自定义的MIME类型,只要符合abc/xyz格式的字符串即可。
- Extra属性通常用于在多个Action之间进行数据交换,Intent的Extra属性值应该是一个Bundle对象。
- Flag属性用于为该Intent添加一些额外的控制旗标
二.Intent的调用方法
1.显示(explicit)调用
显式Intent需要明确指定要启动或者触发的组件的类名
2.隐示(implicit)调用
隐式Intent只是指定需要启动或者触发的组件应满足怎样的条件。对于隐式Intent而言,Android系统需要对该Intent进行解析,解析出它的条件,然后再去系统中查找与之匹配的目标组件。如果找到符合条件的组件,就启动或触发它们。
Implicit intents并不声明要启动组件的具体类名,而是声明一个需要执行的action。这个action指定了我们想做的事情,例如查看,编辑,发送或者是获取一些东西。Intents通常会在发送action的同时附带一些数据,例如你想要查看的地址或者是你想要发送的邮件信息。数据的具体类型取决于我们想要创建的Intent,比如URL或其他规定的数据类型,或者甚至也可能根本不需要数据。
例如:
//打电话 Uri number = Uri.parse("tel:5551234"); Intent callIntent = new Intent(Intent.ACTION_DIAL, number); //看地图 // Map point based on address Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"); // Or map point based on latitude/longitude // Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); //打开网页 Uri webpage = Uri.parse("http://www.android.com"); Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
一些需要其他数据的隐示Intent,我们可以使用putExtra()方法来添加一些数据。如果我们没有在intent中包含一个Uri, 则通常需要使用 setType() 方法来指定intent附带的数据类型。设置MIME type 是为了指定应该接受这个intent的activity。
//发送一个带附件的email Intent emailIntent = new Intent(Intent.ACTION_SEND); // The intent does not have a URI, so declare the "text/plain" MIME type emailIntent.setType(HTTP.PLAIN_TEXT_TYPE); emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipients emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject"); emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text"); emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment")); // You can also attach multiple items by passing an ArrayList of Uris //创建一个日历事件: Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI); Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30); Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()); calendarIntent.putExtra(Events.TITLE, "Ninja class"); calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
验证是否有App去接收这个Intent:
当触发了一个intent,但是没有任何一个app中的activity来接受,则app会crash。所以我们需要确保有intent会被系统内置的app(such as the Phone, Email, or Calendar app)之一接收。为了验证是否有合适的activity会响应这个intent,需要执行queryIntentActivities() 来获取到能够接收这个intent的所有activity的list。若返回的List非空,那么我们才可以安全的使用这个intent。例如:
PackageManager packageManager = getPackageManager(); List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0); boolean isIntentSafe = activities.size() > 0;
显示分享App的选择界面
请注意,当以startActivity()的形式传递一个intent,并且有多个app可以handle时,用户可以在弹出dialog的时候选择默认启动的app(通过勾选dialog下面的选择框,如上图所示)。该功能对于用户有特殊偏好的时候非常有用(例如用户总是喜欢启动某个app来查看网页,总是喜欢启动某个camera来拍照)。
为了显示多个打开方式, 需要使用createChooser()来创建Intent:
Intent intent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. This says something like "Share this photo with" String title = getResources().getText(R.string.chooser_title); // Create and start the chooser Intent chooser = Intent.createChooser(intent, title); startActivity(chooser);
三.接收Activity返回的结果
启动另外一个activity并不一定是单向的。我们也可以启动另外一个activity然后接受一个返回的result。为接受result,我们需要使用startActivityForResult() ,而不是startActivity()。
当然,被启动的activity需要指定返回的result。它需要把这个result作为另外一个intent对象返回,我们的activity需要在onActivityResult()的回调方法里面去接收result。
对于startActivityForResult() 方法中的intent与之前介绍的并无太大差异,不过是需要在这个方法里面多添加一个int类型的参数。
该integer参数称为"request code",用于标识请求。当我们接收到result Intent时,可从回调方法里面的参数去判断这个result是否是我们想要的。
//启动activity static final int PICK_CONTACT_REQUEST = 1; // The request code ... private void pickContact() { Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts")); pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST); } //接收Result /* 当用户完成了启动之后activity操作之后,系统会调用我们activity中的onActivityResult() 回调方法。该方法有三个参数: 通过startActivityForResult()传递的request code。 第二个activity指定的result code。如果操作成功则是RESULT_OK ,如果用户没有操作成功,而是直接点击回退或者其他什么原因,那么则是RESULT_CANCELED 包含了所返回result数据的intent。 */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // Check which request we're responding to if (requestCode == PICK_CONTACT_REQUEST) { // Make sure the request was successful if (resultCode == RESULT_OK) { // The user picked a contact. // The Intent's data Uri identifies which contact was selected. // Do something with the contact here (bigger example below) } } }
处理Intent的activity返回result只需要执行setResult(),通过指定一个result code与result intent。操作完成之后,用户需要返回到原来的activity,通过执行finish() 关闭被唤起的activity。
// Create intent to deliver some kind of result data Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri"); setResult(Activity.RESULT_OK, result); finish();
result code的值通常RESULT_OK或
RESULT_CANCELED(默认)。
如果只是纯粹想要返回一个int来表示某些返回的result数据之一,则可以设置result code为任何大于0的数值。如果我们返回的result只是一个int,那么连intent都可以不需要返回了,可以调用setResult()。
setResult(RESULT_COLOR_RED); finish();
四.Intent过滤
通过在manifest文件中的<activity>标签下添加<intent-fliter>的属性,使其他的app能够启动我们的activity。
为了尽可能确切的定义activity能够handle的intent,每一个intent filter都应该尽可能详尽的定义好action与data。
-
Action:一个想要执行的动作的名称。通常是系统已经定义好的值,如
ACTION_SEND
或ACTION_VIEW
。 在intent filter中通过<action>
指定它的值,值的类型必须为字符串,而不是API中的常量(看下面的例子) -
Data:Intent附带数据的描述。在intent filter中通过
<data>
指定它的值,可以使用一个或者多个属性,我们可以只定义MIME type或者是只指定URI prefix,也可以只定义一个URI scheme,或者是他们综合使用。
- Category:提供一个附加的方法来标识这个activity能够handle的intent。通常与用户的手势或者是启动位置有关。系统有支持几种不同的categories,但是大多数都很少用到。而且,所有的implicit intents都默认是 CATEGORY_DEFAULT 类型的。在intent filter中用
<category>
指定它的值。
<activity android:name="ShareActivity"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> <data android:mimeType="image/*"/> </intent-filter> </activity>