近期在构建新项目的时候,发现 onActivityResult 方法已经被废弃了,于是有了尝试 registerForActivityResult 的想法。
# 标准使用
三个类 ActivityResultLauncher 、 ActivityResultContract 、 ActivityResultCallback
首先 ActivityResultLauncher 作为主角,它需要配置一个泛型,这个泛型跟我们 ActivityResultContract 的返回值相同, ActivityResultLauncher 通过 launch 方法来启动相应的界面或者功能。
- ActivityResultContract
public static class GalleryContract extends ActivityResultContract<Void, Uri> { | |
@NonNull | |
@Override | |
public Intent createIntent(@NonNull Context context, Void input) { | |
Intent intent = new Intent(); | |
intent.setAction(Intent.ACTION_PICK); | |
intent.setType("image/*"); | |
return intent; | |
} | |
@Override | |
public Uri parseResult(int resultCode, @Nullable Intent intent) { | |
return intent.getData(); | |
} | |
} |
可以看到 ActivityResultContract 需要传入两个泛型,一个泛型作为 createIntent 方法的第二参数类型,这里可以作为我们 intent 传值的参数载体, ActivityResultContract 的另一个泛型作为 parseResult 方法的返回值类型,我们可以自行定义从 intent 返回的参数类型。
- ActivityResultLauncher
private ActivityResultLauncher<Void> galleryLauncher = registerForActivityResult(new GalleryContract(), new ActivityResultCallback<Uri>() { | |
@Override | |
public void onActivityResult(Uri result) { | |
//todo something | |
} | |
}); |
把 contract 和 ActivityResultCallback 作为 launcher 的参数构建出 launcher
- ActivityResultCallback
这个里面就和onActivityResult方法回调一样的,只不过提供的结果参数是我们在 contract 中定义的。
4. 启动 launch
通过 galleryLauncher.launch(null); 启动即可。
# 简单使用
ActivityResultContracts
这个类中提供了许多通用的方法
| ActivityResultContracts.* | 说明 | 参数 | 回调 |
|---|---|---|---|
| StartActivityForResult | 可以理解为 startActivityForResult | Intent | ActivityResult(code,data) |
| TakePicture | 通过 MediaStore.ACTION_IMAGE_CAPTURE 拍照并保存 | 保存文件的 Uri | 是否保存成功 |
| TakePicturePreview | 通过 MediaStore.ACTION_IMAGE_CAPTURE 拍照,但是只会拍一张小照片,作为 thumbnail 使用比较合适 | null(Void) | 图片的 Bitmap |
| CaptureVideo | 通过 MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频并保存 (androidx.activity 1.3.0-alpha08 后提供,androidx.appcompat 好像还没提供该类) | 保存文件的 Uri | 是否保存成功。 |
| RequestPermission | 请求单个权限 | Manifest.permission.* | 用户是否授予该权限 |
| RequestMultiplePermissions | 请求多个权限 | Array | 回调为 map, key 为请求的权限,value 为用户是否授予该权限 |
| CreateDocument | 通过 Intent.ACTION_CREATE_DOCUMENT 创建一个文件 | 默认文件名 | 选择目录后返回该文件的 Uri |
| GetContent | 通过 Intent.ACTION_GET_CONTENT 获取一个文件 (这个方法可以通过 android.content.ContentResolver.openInputStream 获取到文件的原始数据) | MIME 类型 | 文件 Uri |
| GetMultipleContents | 通过 Intent.ACTION_GET_CONTENT 及 Intent.EXTRA_ALLOW_MULTIPLE 获取一个或多个文件 (这个方法可以通过 android.content.ContentResolver.openInputStream 获取到文件的原始数据) | MIME 类型 | 文件 List |
| OpenDocument | 通过 Intent.ACTION_OPEN_DOCUMENT 选择文件 | MIME 类型 | 文件 Uri |
| OpenDocumentTree | 通过 Intent.ACTION_OPEN_DOCUMENT_TREE 选择一个目录,返回一个 Uri 并得到该目录下全部文档的管理权 | 目录初始位置 Uri | 选择目录 Uri |
| OpenMultipleDocuments | 通过 Intent.ACTION_OPEN_DOCUMENT 及 Intent.EXTRA_ALLOW_MULTIPLE 获取一个或多个文件 | MIME 类型 | 文件 List |
| PickContact | 通过 Intent.ACTION_PICK 从系统通讯录中获取联系人 | null(Void) | 联系人 Uri |
| StartIntentSenderForResult* | 构建 IntentSender 或 PendingIntent | 使用 IntentSenderRequest.Builder 构建 | ActivityResult(code,data) |
| TakeVideo | 通过 MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频并保存 (弃用了,官方解释是缩略图的 Bitmap 的返回不稳定,替换为上面的 CaptureVideo 即可) | 保存文件的 Uri | 视频缩略图 Bitmap |
类似的使用如下
private ActivityResultLauncher<String> fileLauncher = registerForActivityResult(new ActivityResultContracts.GetContent(), new ActivityResultCallback<Uri>() { | |
@Override | |
public void onActivityResult(Uri result) { | |
} | |
}); |
private ActivityResultLauncher<Uri> videoLauncher = registerForActivityResult(new ActivityResultContracts.CaptureVideo(), new ActivityResultCallback<Boolean>() { | |
@Override | |
public void onActivityResult(Boolean result) { | |
} | |
}); |
# 注意
不能在需要使用的时候再去构建我们需要的 launcher,否则会抛出异常
在 Activity 中
在 Fragment 中