背景

startActivityForResult()方法过期了!!!

原因是onActivityResult()方法中代码逻辑复杂,混乱。

研究

Android推出了新的API,Activity Results API。

学习文档:https://mp.weixin.qq.com/s/lWayiBS4T4EHcsUIgnhJzA

Demo

  • ActivityResultContract: 协议,它定义了如何传递数据和如何处理返回的数据。ActivityResultContract是一个抽象类,你需要继承它来创建自己的协议,每个 ActivityResultContract 都需要定义输入和输出类,如果您不需要任何输入,可使用 Void(在 Kotlin 中,使用 Void? 或 Unit)作为输入类型。
  • ActivityResultLauncher: 启动器,调用ActivityResultLauncher的launch方法来启动页面跳转,作用相当于原来的startActivity()
  1. //选择本地照片例子
  2. void selectImage() {
  3. String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
  4. if (hasPermission(permissions)) {
  5. launcher.launch(1);
  6. } else {
  7. initPermissions(permissions, new PermissionResult() {
  8. @Override
  9. public void onSuccess() {
  10. launcher.launch(1);
  11. }
  12. @Override
  13. public void onFailure() {
  14. toast("请授予读写权限");
  15. }
  16. @Override
  17. public void onFailureWithNeverAsk() {
  18. toast("请到应用设置中授予读写权限");
  19. }
  20. });
  21. }
  22. }
  23. ActivityResultLauncher<Integer> launcher = registerForActivityResult(new ResultContract(), new ActivityResultCallback<Bitmap>() {
  24. @Override
  25. public void onActivityResult(Bitmap result) {
  26. binding.image.setImageBitmap(result);
  27. }
  28. });
  29. //Integer是输入类型,Bitmap是输出类型
  30. class ResultContract extends ActivityResultContract<Integer, Bitmap> {
  31. @NonNull
  32. @Override
  33. public Intent createIntent(@NonNull Context context, Integer input) {
  34. Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
  35. intent.addCategory(Intent.CATEGORY_OPENABLE);
  36. intent.setType("image/*");
  37. return intent;
  38. }
  39. @Override
  40. public Bitmap parseResult(int resultCode, @Nullable Intent intent) {
  41. if (resultCode == RESULT_OK) {
  42. if (intent != null) {
  43. Uri uri = intent.getData();
  44. if (uri != null) {
  45. try {
  46. ParcelFileDescriptor descriptor = getContentResolver().openFileDescriptor(uri, "r");
  47. if (descriptor != null) {
  48. Bitmap bitmap = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor());
  49. return bitmap;
  50. }
  51. } catch (FileNotFoundException e) {
  52. e.printStackTrace();
  53. }
  54. }
  55. }
  56. }
  57. return null;
  58. }
  59. }

对于每次定义Contract的问题!!!

官方定义的Contract

  • StartActivityForResult: 通用的Contract,不做任何转换,Intent作为输入,ActivityResult作为输出,这也是最常用的一个协定。
  • RequestMultiplePermissions:用于请求一组权限
  • RequestPermission: 用于请求单个权限
  • TakePicturePreview: 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,返回值为Bitmap图片
  • TakePicture: 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,并将图片保存到给定的Uri地址,返回true表示保存成功。
  • TakeVideo: 调用MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频,保存到给定的Uri地址,返回一张缩略图。
  • PickContact: 从通讯录APP获取联系人
  • GetContent: 提示用选择一条内容,返回一个通过ContentResolver#openInputStream(Uri)访问原生数据的Uri地址(content://形式) 。默认情况下,它增加了Intent#CATEGORY_OPENABLE, 返回可以表示流的内容。
  • CreateDocument: 提示用户选择一个文档,返回一个(file:/http:/content:)开头的Uri。
  • OpenMultipleDocuments: 提示用户选择文档(可以选择多个),分别返回它们的Uri,以List的形式。
  • OpenDocumentTree: 提示用户选择一个目录,并返回用户选择的作为一个Uri返回,应用程序可以完全管理返回目录中的文档。

优点

不用第三方权限框架了

  1. request_permission.setOnClickListener {
  2. requestPermission.launch(permission.BLUETOOTH)
  3. }
  4. request_multiple_permission.setOnClickListener {
  5. requestMultiplePermissions.launch(
  6. arrayOf(
  7. permission.BLUETOOTH,
  8. permission.NFC,
  9. permission.ACCESS_FINE_LOCATION
  10. )
  11. )
  12. }
  13. // 请求单个权限
  14. private val requestPermission =
  15. registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
  16. // Do something if permission granted
  17. if (isGranted) toast("Permission is granted")
  18. else toast("Permission is denied")
  19. }
  20. // 请求一组权限
  21. private val requestMultiplePermissions =
  22. registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions : Map<String, Boolean> ->
  23. // Do something if some permissions granted or denied
  24. permissions.entries.forEach {
  25. // Do checking here
  26. }
  27. }