近期在构建新项目的时候,发现 onActivityResult 方法已经被废弃了,于是有了尝试 registerForActivityResult 的想法。

# 标准使用

三个类 ActivityResultLauncherActivityResultContractActivityResultCallback
首先 ActivityResultLauncher 作为主角,它需要配置一个泛型,这个泛型跟我们 ActivityResultContract 的返回值相同, ActivityResultLauncher 通过 launch 方法来启动相应的界面或者功能。

  1. 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 返回的参数类型。

  1. ActivityResultLauncher
private ActivityResultLauncher<Void> galleryLauncher = registerForActivityResult(new GalleryContract(), new ActivityResultCallback<Uri>() {
        @Override
        public void onActivityResult(Uri result) {
            //todo something
        }
    });

把 contract 和 ActivityResultCallback 作为 launcher 的参数构建出 launcher

  1. ActivityResultCallback
    这个里面就和 onActivityResult 方法回调一样的,只不过提供的结果参数是我们在 contract 中定义的。

4. 启动 launch
通过 galleryLauncher.launch(null); 启动即可。

# 简单使用

ActivityResultContracts
这个类中提供了许多通用的方法

ActivityResultContracts.*说明参数回调
StartActivityForResult可以理解为 startActivityForResultIntentActivityResult(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