作者:郭孝星
微博:郭孝星的新浪微博
博客:http://blog.csdn.net/allenwells
Github:https://github.com/AllenWells
一 Intent验证
尽管Android系统会确保每一个确定的intent会被系统内置的app(such as the Phone, Email, or Calendar app)之一接收,但是我们还是应该在触发一个intent之前做验证是否有App接受这个intent的步骤,因为如果我们触发了一个intent,而且没有任何一个App会去接收这个intent,那么我们的App会崩溃。
为了验证是否有合适的Activity会响应这个Intent,需要执行queryIntentActivities()来获取到能够接收这个Intent的所有Activity的list。如果返回的List非空,那么我们就可以安全的使用这个Intent,如下所示:
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
当我们创建好了Intent并且设置好了extra数据,通过执行startActivity(intent)来发送到系统。如果系统确定有多个Activity可以handle这个Intent,它会显示出一个Dialog,让用户选择启动哪个App。如果系统发现只有一个App可以handle这个Intent,那么就会直接启动这个App,如下所示:
举例
创建一个Intent来查看地图,验证有App可以handle这个Intent,然后启动它。
// Build the intent
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
// Verify it resolves
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;
// Start an activity if it‘s safe
if (isIntentSafe) {
startActivity(mapIntent);
}
二 Intent发送
(1) 启动Activity
启动另外一个Activity并不一定是单向的。我们也可以启动另外一个Activity然后接受一个result回来。为了接收这个result,我们需要使用startActivityForResult(),而不startActivity(),如下所示:
举例
启动Activity来选择联系人
static final int PICK_CONTACT_REQUEST = 1; // The request code
...
private void pickContact() {
Intent pickContactIntent = new Intent(Intent.ACTION_PICK, new Uri("content://contacts"));
pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}
(2) 接收Result
当用户完成了启动之后Activity操作之后,系统会调用你的Activity的onActivityResult()回调方法。这个方法有三个参数,如下所示:
- 第一个通过startActivityForResult()传递的request code。
- 第二个activity指定的result code。如果操作成功则是 RESULT_OK ,如果用户没有操作成功,而是直接点击回退或者其他什么原因,那么则是RESULT_CANCELED。
- 第三个参数则是intent,它包含了返回的result数据部分。
举例
处理选择联系人返回结果。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request it is that we‘re responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// Get the URI that points to the selected contact
Uri contactUri = data.getData();
// We only need the NUMBER column, because there will be only one row in the result
String[] projection = {Phone.NUMBER};
// Perform the query on the contact to get the NUMBER column
// We don‘t need a selection or sort order (there‘s only one result for the given URI)
// CAUTION: The query() method should be called from a separate thread to avoid blocking
// your app‘s UI thread. (For simplicity of the sample, this code doesn‘t do that.)
// Consider using CursorLoader to perform the query.
Cursor cursor = getContentResolver()
.query(contactUri, projection, null, null, null);
cursor.moveToFirst();
// Retrieve the phone number from the NUMBER column
int column = cursor.getColumnIndex(Phone.NUMBER);
String number = cursor.getString(column);
// Do something with the phone number...
}
}
}
三 Intent过滤
为了尽可能确切的定义Activity能够handle哪些Intent,每一个intent filter都应该尽可能详尽的定义好action与data。如果Activity中的Intent Filter满足以下Intent对象的标准,系统就能够把特定的Intent发送给Activity,如下所示:
- Action:一个想要执行的动作的名称。通常是系统已经定义好的值,例如 ACTION_SEND 或者 ACTION_VIEW 。 在intent filt
中用 指定它的值,值的类型必须为字符串,而不是API中的常量。
- Data:Intent附带数据的描述。在intent filter中用 指定它的值,可以使用一个或者多个属性,可以只定义MIME type或者是只指定Uri prefix,也可以只定义一个Uri Scheme,或者是它们综合使用。
- Note:如果不想handle Uri类型的数据,那么我们应该指定android:mimeType属性。例如text/plain或者image/jpeg。
- Category:提供一个附加的方法来标识这个Activity能够handle的Intent。通常与用户的手势或者是启动位置有关。系统有支持几种不同的Categories,但是大多数都不怎么用的到。而且,所有的implicit intents都默认是CATEGORY_DEFAULT类型的。在Intent Filter中用指定它的值。
在intent filter中,我们可以在元素中定义对应的XML元素来声明Activity使用何种标准。
举例
当数据类型为文本或图像时会处理ACTION_SEND的Intent。
<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>
每一个发送出来的Intent只会包含一个Action与Data类型,但是handle这个Intent的Activity的是可以声明多个 、与的。如果任何的两对Action与Data是互相矛盾的,我们应该创建不同的Intent Filter来指定特定的Action与Type。
举例
Activity可以handle文本与图片,无论是ACTION_SEND还是ACTION_SENDTO的Intent。在这种情况下,我们需要为两个Action定义两个不同的Intent Filter。因为ACTION_SENDTO的Intent必须使用Uri类型来指定接收者使用send或sendTo的地址,如下所示:
<activity android:name="ShareActivity">
<!-- filter for sending text; accepts SENDTO action with sms URI schemes -->
<intent-filter>
<action android:name="android.intent.action.SENDTO"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="sms" />
<data android:scheme="smsto" />
</intent-filter>
<!-- filter for sending text or images; accepts SEND action and text or image data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/*"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
注意:为了接收Intent, 我们需要在Intent Filter中包含CATEGORY_DEFAULT的category。startActivity()和startActivityForResult()方法将所有intent视为声明了CATEGORY_DEFAULT category。如果没有在Intent Filter中声明CATEGORY_DEFAULT,那么Activity将无法对隐式Intent做出响应。
版权声明:本文为博主原创文章,未经博主允许不得转载。