启用另一个activity不一定是单向的。也可以启用另一个activity并且获得返回值。要获得返回值的话,调用startActivityForResult()(而不是startActivity())。
比如,app可以打开相机然后接收一张照片作为返回值。或者,为了让用户选择一个联系人可以让用户启动联系人相关app,然后收到联系人详情作为结果。
当然,这个响应的activity必须设计为有返回值的。当返回的时候,它用Intent对象作为返回值。activity会在onActivityResult()回调方法中收到。
注意:用明确的和模糊的intent都可以使用startActivityForResult()。当使用自己的activity来接收结果时,需要使用一个明确的intent来保证你可以收到结果。
开始一个Activity
当启动一个activity来获取返回值时Intent对象没有什么特别的,但是需要另外传递一个integer参数给startActivityForResult()方法。
这个integer参数是一个"request code",用来标识请求。当收到Intent结果,回调时会返回同样的"request code"这样app可以很好的识别结果和决定如何处理它。
例如,这里有一个如何启动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);
}
接收返回值
当用户完成了后来activity中的操作并且返回时,系统会调用activity的onActivityResult()方法。这个方法包含三个参数:
- 在startActivityForResult()中传递的请求码。
- 第二个activity的返回码。它会时RESULT_OK如果操作成功,或者RESULT_CANCELED如果用户退回去或者操作由于某些原因失败。
- 一个带有结果数据的Intent
例如,这里是如何处理选择联系人的返回值:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 检查返回的结果
if (requestCode == PICK_CONTACT_REQUEST) {
// 确保请求成功了
if (resultCode == RESULT_OK) {
// 用户选择了一个联系人
// Intent的数据Uri标识了联系人被选中了 // 用这个联系人做点什么(下面会有示例)
}
}
}
这个例子中,由Android联系人或其他联系人相关app返回的Intent提供了一个Uri可以标识用户选择了哪个联系人。
为了成功的处理结果,必须要了解返回的Intent的格式是什么样的。当返回值的activity是自己的activity时处理起来很简单。Android平台自带的app,对于这些结果可以根据他们提供的API来处理。例如,联系人app总是返回一个content URI来标识选中的联系人,相机app在附加数据中返回一个Bitmap(可以在Capturing Photos中查看)。
附加:读取联系人数据
上面的代码展示了如何从联系人app中获得结果但是没有详细的展示如何读结果数据,因为需要更多的关于content providers的探讨。然而,如果你好奇的话,这里由一些代码展示了如果从选择的联系人中获得电话号码:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 查看返回的是哪个请求
if (requestCode == PICK_CONTACT_REQUEST) {
// 确保请求成功了
if (resultCode == RESULT_OK) {
// 获得指向选中联系人的URI
Uri contactUri = data.getData();
// 我们只需要NUMBER列,因为结果中只有一行
String[] projection = {Phone.NUMBER}; // 在联系人上执行查询来获得NUMBER列
// 我们不需要选择排序方法(只有一个结果)
// 注意:query()应该在另外一个线程调用,为了避免阻塞app的UI线程。(为了简单,这里就不那么做了)
// 用CursorLoader来执行查询
Cursor cursor = getContentResolver()
.query(contactUri, projection, null, null, null);
cursor.moveToFirst(); //从NUMBER列获得电话号码
int column = cursor.getColumnIndex(Phone.NUMBER);
String number = cursor.getString(column); //用电话号码所点什么
}
}
}
注意:在Android2.3(API等级9)之前,使用Contracts Provider(就像上面展示的)来查询需要app声明READ_CONTACTS权限(查看Security and Permissions)。然后,从Android2.3开始,联系人app允许app用临时权限来用Contacts Provider获得结果。这个临时权限只适用于明确的联系人请求,所以除非是由intent的Uri明确指定的联系人,其他的都不能查询,或者可以声明READ_CONTACTS权限。