Android ActivityResult 介绍

Android ActivityResult 介绍

ActivityResult API 是 androidx.activity:activity 包引入的新 API,用来替代原有的 onActivityResult 获取上一个 Activity 返回的结果。

被废弃的 startActivityForResult 和 onActivityResult

startActivityForResult

从 ComponentActivity 的 startActivityForResult 方法 @Deprecated 注解可以看出这个方法已经被废弃,建议使用 registerForActivityResult 替代。

    /**
     * {@inheritDoc}
     *
     * @deprecated use
     * {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)}
     * passing in a {@link StartActivityForResult} object for the {@link ActivityResultContract}.
     */
    @Override
    @Deprecated
    public void startActivityForResult(@SuppressLint("UnknownNullness") Intent intent,
            int requestCode) {
        super.startActivityForResult(intent, requestCode);
    }

onActivityResult

从 ComponentActivity 的 onActivityResult 方法 @Deprecated 注解可以看出这个方法已经被废弃,建议使用 registerForActivityResult 替代。


    /**
     * {@inheritDoc}
     *
     * @deprecated use
     * {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)}
     * with the appropriate {@link ActivityResultContract} and handling the result in the
     * {@link ActivityResultCallback#onActivityResult(Object) callback}.
     */
    @CallSuper
    @Override
    @Deprecated
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (!mActivityResultRegistry.dispatchResult(requestCode, resultCode, data)) {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

ActivityResult 用法

registerForActivityResult

registerForActivityResult 是 ComponentActivity 的 public 方法,它接收一个 ActivityResultContract 和一个 ActivityResultCallback。

ActivityResultContract

ActivityResultContract 表示本次 Activity 启动的类型。

如果启动一个需要返回结果的 Activity,可以使用 ActivityResultContracts.StartActivityForResult()。

如果启动一个权限 Activity,就可以使用 ActivityResultContracts.RequestPermission()。

如果需要使用照片预览,可以使用 ActivityResultContracts.TakePicturePreview()。

ActivityResultCallback

ActivityResultCallback 表示上一个 Activity 回传的 ActivityResult 结果。

用法

首先使用 registerForActivityResult 得到 ActivityResultLauncher,在闭包中写上需要处理的ActivityResult。

    private val activityResultLauncher: ActivityResultLauncher<Intent> =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult: ActivityResult ->
            if (activityResult.resultCode == Activity.RESULT_OK) {
                // 收到 ActivityResult
            }
        }

如果要启动一个 Activity,使用 activityResultLauncher 的 launch 方法,替代原来的 startActivityForResult。

            activityResultLauncher.launch(Intent(this, SecondActivity::class.java))

在需要返回结果的被启动 Activity 调用 setResult。

            setResult(Activity.RESULT_OK, Intent().putExtra("key", "value"))
            finish()

ActivityResult 好处

registerForActivityResult 的第一个参数 ActivityResultContracts 封装了很多常用的启动类型。不再需要调用者写不同 Activity 的启动代码。

使用 registerForActivityResult 之后也不需要再为 startActivityForResult 定义 requestCode。

ActivityResultContracts 有 14 个封装好的子类。

StartActivityForResult

常用的 Activity 启动,不带任何转换。

        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, @NonNull Intent input) {
            return input;
        }

StartIntentSenderForResult

启动 IntentSender,调用了 Activity 的 startIntentSender 方法。

        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, @NonNull IntentSenderRequest input) {
            return new Intent(ACTION_INTENT_SENDER_REQUEST)
                    .putExtra(EXTRA_INTENT_SENDER_REQUEST, input);
        }

RequestMultiplePermissions

请求多个权限

        @NonNull
        static Intent createIntent(@NonNull String[] input) {
            return new Intent(ACTION_REQUEST_PERMISSIONS).putExtra(EXTRA_PERMISSIONS, input);
        }

解析 Intent 调用了 ContextCompat.checkSelfPermission 方法。

        @Override
        public @Nullable SynchronousResult<Map<String, Boolean>> getSynchronousResult(
                @NonNull Context context, @Nullable String[] input) {

            if (input == null || input.length == 0) {
                return new SynchronousResult<>(Collections.<String, Boolean>emptyMap());
            }

            Map<String, Boolean> grantState = new ArrayMap<>();
            boolean allGranted = true;
            for (String permission : input) {
                boolean granted = ContextCompat.checkSelfPermission(context, permission)
                        == PackageManager.PERMISSION_GRANTED;
                grantState.put(permission, granted);
                if (!granted) allGranted = false;
            }

            if (allGranted) {
                return new SynchronousResult<>(grantState);
            }
            return null;
        }

RequestPermission

请求单个权限,间接调用了 RequestMultiplePermissions

        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, @NonNull String input) {
            return RequestMultiplePermissions.createIntent(new String[] { input });
        }

TakePicturePreview

照片预览。构造 MediaStore.ACTION_IMAGE_CAPTURE 的 Intent。

new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

TakePicture

拍照并保存。传递 URI 作为保存路径。

        public Intent createIntent(@NonNull Context context, @NonNull Uri input) {
            return new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
                    .putExtra(MediaStore.EXTRA_OUTPUT, input);
        }

TakeVideo

录像并保存。

        public Intent createIntent(@NonNull Context context, @NonNull Uri input) {
            return new Intent(MediaStore.ACTION_VIDEO_CAPTURE)
                    .putExtra(MediaStore.EXTRA_OUTPUT, input);
        }

PickContact

选择通讯录

        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, @Nullable Void input) {
            return new Intent(Intent.ACTION_PICK).setType(ContactsContract.Contacts.CONTENT_TYPE);
        }

GetContent

根据 Uri 从 ContentResolver 加载内容。

        public Intent createIntent(@NonNull Context context, @NonNull String input) {
            return new Intent(Intent.ACTION_GET_CONTENT)
                    .addCategory(Intent.CATEGORY_OPENABLE)
                    .setType(input);
        }

GetMultipleContents

根据 Uri 从 ContentResolver 加载多个内容。

        @CallSuper
        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, @NonNull String input) {
            return new Intent(Intent.ACTION_GET_CONTENT)
                    .addCategory(Intent.CATEGORY_OPENABLE)
                    .setType(input)
                    .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        }

OpenDocument

打开文档。

        @CallSuper
        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, @NonNull String[] input) {
            return new Intent(Intent.ACTION_OPEN_DOCUMENT)
                    .putExtra(Intent.EXTRA_MIME_TYPES, input)
                    .setType("*/*");
        }

OpenMultipleDocuments

打开多个文档。

        @CallSuper
        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, @NonNull String[] input) {
            return new Intent(Intent.ACTION_OPEN_DOCUMENT)
                    .putExtra(Intent.EXTRA_MIME_TYPES, input)
                    .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
                    .setType("*/*");
        }

OpenDocumentTree

打开目录。

        @CallSuper
        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, @Nullable Uri input) {
            Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
                    && input != null) {
                intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, input);
            }
            return intent;
        }

CreateDocument

创建文档

        @CallSuper
        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, @NonNull String input) {
            return new Intent(Intent.ACTION_CREATE_DOCUMENT)
                    .setType("*/*")
                    .putExtra(Intent.EXTRA_TITLE, input);
        }

ActivityResult 原理

ActivityResult 使用 ActivityResultLauncher 的 launch 方法代替了 startActivityForResult。

            activityResultLauncher.launch(Intent(this, SecondActivity::class.java))

ActivityResultLauncher 是一个抽象类,它的 launch 方法如下:

ActivityResultLauncher

launch 方法调用了 2 个参数的 launch 抽象方法。

    public void launch(@SuppressLint("UnknownNullness") I input) {
        launch(input, null);
    }

    public abstract void launch(@SuppressLint("UnknownNullness") I input,
            @Nullable ActivityOptionsCompat options);

registerForActivityResult

ComponentActivity 的 registerForActivityResult 方法调用了 registry 的 register 方法。mActivityResultRegistry 是 ComponentActivity 的私有类变量。

    @NonNull
    @Override
    public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
            @NonNull final ActivityResultContract<I, O> contract,
            @NonNull final ActivityResultRegistry registry,
            @NonNull final ActivityResultCallback<O> callback) {
        return registry.register(
                "activity_rq#" + mNextLocalRequestCode.getAndIncrement(), this, contract, callback);
    }

    @NonNull
    @Override
    public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
            @NonNull ActivityResultContract<I, O> contract,
            @NonNull ActivityResultCallback<O> callback) {
        return registerForActivityResult(contract, mActivityResultRegistry, callback);
    }

ActivityResultRegistry

ComponentActivity 的 mActivityResultRegistry 实现 ActivityResultRegistry 类的 onLaunch 抽象方法,表示 Intent 启动时需要做的事情。

ActivityResultRegistry.onLaunch
    private final ActivityResultRegistry mActivityResultRegistry = new ActivityResultRegistry() {

        @Override
        public <I, O> void onLaunch(
                final int requestCode,
                @NonNull ActivityResultContract<I, O> contract,
                I input,
                @Nullable ActivityOptionsCompat options) {
            ComponentActivity activity = ComponentActivity.this;

            // Immediate result path
            final ActivityResultContract.SynchronousResult<O> synchronousResult =
                    contract.getSynchronousResult(activity, input);
            // 1. 如果有同步结果,发到主线程执行。
            if (synchronousResult != null) {
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        dispatchResult(requestCode, synchronousResult.getValue());
                    }
                });
                return;
            }

            // 2. 从 ActivityResultContract 的 createIntent 方法获取 目标Intent。
            // Start activity path
            Intent intent = contract.createIntent(activity, input);
            ...
            // 3. 处理权限请求。
            if (ACTION_REQUEST_PERMISSIONS.equals(intent.getAction())) {
            ...
                ActivityCompat.requestPermissions(activity, permissions, requestCode);
            } else if (ACTION_INTENT_SENDER_REQUEST.equals(intent.getAction())) {
            ...
            // 4. 处理 IntentSender。
                ...
                    ActivityCompat.startIntentSenderForResult(activity, request.getIntentSender(),
                            requestCode, request.getFillInIntent(), request.getFlagsMask(),
                            request.getFlagsValues(), 0, optionsBundle);
                ...
            } else {
            // 5. 其他情况调用 startActivityForResult
                // startActivityForResult path
                ActivityCompat.startActivityForResult(activity, intent, requestCode, optionsBundle);
            }
        }
    };
ActivityResultRegistry.register

ActivityResultRegistry 的 register 方法返回了一个匿名内部类 ActivityResultLauncher,ActivityResultLauncher 的 launch 方法调用了 ActivityResultRegistry 的 onLaunch。

register 方法如下:

    @NonNull
    public final <I, O> ActivityResultLauncher<I> register(
            @NonNull final String key,
            @NonNull final LifecycleOwner lifecycleOwner,
            @NonNull final ActivityResultContract<I, O> contract,
            @NonNull final ActivityResultCallback<O> callback) {

        ...
        LifecycleEventObserver observer = new LifecycleEventObserver() {
            @Override
            public void onStateChanged(
                    @NonNull LifecycleOwner lifecycleOwner,
                    @NonNull Lifecycle.Event event) {
                if (Lifecycle.Event.ON_START.equals(event)) {
                    mKeyToCallback.put(key, new CallbackAndContract<>(callback, contract));
                    if (mParsedPendingResults.containsKey(key)) {
                        ...
                        // 1. 预解析的同步的 ActivityResult
                        callback.onActivityResult(parsedPendingResult);
                    }
                    final ActivityResult pendingResult = mPendingResults.getParcelable(key);
                    if (pendingResult != null) {
                        ...
                        // 2. 先调用 contract 解析,再返回 ActivityResult
                        callback.onActivityResult(contract.parseResult(
                                pendingResult.getResultCode(),
                                pendingResult.getData()));
                    }
                } else if (Lifecycle.Event.ON_STOP.equals(event)) {
                    mKeyToCallback.remove(key);
                } else if (Lifecycle.Event.ON_DESTROY.equals(event)) {
                    unregister(key);
                }
            }
        };
        ...

        return new ActivityResultLauncher<I>() {
        
            // 3. launch 方法。
            @Override
            public void launch(I input, @Nullable ActivityOptionsCompat options) {
                mLaunchedKeys.add(key);
                // 4. 回调 ActivityResultRegistry 的 onLaunch 方法。
                // 间接调用 ComponentActivity 的 startActivityForResult。
                onLaunch(requestCode, contract, input, options);
            }

            @Override
            public void unregister() {
                ActivityResultRegistry.this.unregister(key);
            }

            @NonNull
            @Override
            public ActivityResultContract<I, ?> getContract() {
                return contract;
            }
        };
    }

总结

ActivityResult API 是 androidx.activity:activity 包引入的新 API,用来替代原有的 onActivityResult、requestCode 和 startActivityForResult。

ActivityResult 预置了一些常用的 Activity 启动类型,使用更为方便。

ActivityResultLauncher 的 launch 本质是在 ComponentActivity 的 ActivityResultRegistry 的 onLaunch 调用 startActivityForResult 启动 Activity。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Image Cropper 是一个开源的图片裁剪库,可以快速地实现图片的裁剪功能。它支持手势缩放和移动,可以裁剪任意比例的图片,同时也支持圆形裁剪。 使用 Android Image Cropper 很简单,只需要添加以下依赖: ```groovy implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.+' ``` 然后在代码中使用 CropImageActivity 来启动图片裁剪界面: ```java CropImage.activity(imageUri) .setGuidelines(CropImageView.Guidelines.ON) .setAspectRatio(1, 1) .setCropShape(CropImageView.CropShape.RECTANGLE) .start(this); ``` 其中,imageUri 是要裁剪的图片的 Uri,setGuidelines 方法用于设置裁剪界面上的辅助线,setAspectRatio 方法用于设置裁剪的宽高比,setCropShape 方法用于设置裁剪的形状,可以选择矩形或圆形。 在 onActivityResult 方法中处理裁剪后的图片: ```java @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) { CropImage.ActivityResult result = CropImage.getActivityResult(data); if (resultCode == RESULT_OK) { Uri croppedUri = result.getUri(); // 处理裁剪后的图片 } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) { Exception error = result.getError(); // 处理裁剪错误 } } } ``` 在这个示例代码中,我们使用 CropImage.activity 方法启动图片裁剪界面,并在 onActivityResult 方法中获取裁剪后的图片的 Uri。如果裁剪成功,可以从 Uri 中获取裁剪后的图片,并进行后续处理。如果裁剪失败,可以从 CropImage.ActivityResult 中获取错误信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值