Android深入学习之ComponentActivity.registerForActivityResult()方法

发布时间 2023-11-23 20:05:51作者: 南风小斯

ComponentActivity.startActivityForResult()和ComponentActivity.onActivityResult()已经废弃,如下图所示,取而代之的是统一它俩的ActivityResultLauncher。

  

ActivityResultLauncher对象可以通过ComponentActivity.registerForActivityResult()方法获取。该方法有两个重载。

public final @NonNull ActivityResultLauncher<I> <I, O> registerForActivityResult(
    @NonNull ActivityResultContract<I, O> contract,
    @NonNull ActivityResultCallback<O> callback
)

public final @NonNull ActivityResultLauncher<I> <I, O> registerForActivityResult(
    @NonNull ActivityResultContract<I, O> contract,
    @NonNull ActivityResultRegistry registry,
    @NonNull ActivityResultCallback<O> callback
)

第一个registerForActivityResult()方法的源代码如下:

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

它拿着mActivityResultRegistry对象去调用了第二个registerForActivityResult()方法。第二个registerForActivityResult()方法的源代码如下:

@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);
    }

mActivityResultRegistry是ComponentActivity中定义并初始化的一个ActivityResultRegistry类型变量。

ActivityResultRegistry是个抽象类,其中定义的抽象方法是

@MainThread
public abstract void <I, O> onLaunch(
    int requestCode,
    @NonNull ActivityResultContract<I, O> contract,
    I input,
    @Nullable ActivityOptionsCompat options
)

此外还有两个被final修饰的register()方法

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

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

上方registerForActivityResult()方法就是调用了第二个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) {

        Lifecycle lifecycle = lifecycleOwner.getLifecycle();

        if (lifecycle.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
            throw new IllegalStateException("LifecycleOwner " + lifecycleOwner + " is "
                    + "attempting to register while current state is "
                    + lifecycle.getCurrentState() + ". LifecycleOwners must call register before "
                    + "they are STARTED.");
        }

        registerKey(key);
        LifecycleContainer lifecycleContainer = mKeyToLifecycleContainers.get(key);
        if (lifecycleContainer == null) {
            lifecycleContainer = new LifecycleContainer(lifecycle);
        }
        LifecycleEventObserver observer = new LifecycleEventObserver() {
            @Override
            @SuppressWarnings("deprecation")
            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)) {
                        @SuppressWarnings("unchecked")
                        final O parsedPendingResult = (O) mParsedPendingResults.get(key);
                        mParsedPendingResults.remove(key);
                        callback.onActivityResult(parsedPendingResult);
                    }
                    final ActivityResult pendingResult = mPendingResults.getParcelable(key);
                    if (pendingResult != null) {
                        mPendingResults.remove(key);
                        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);
                }
            }
        };
        lifecycleContainer.addObserver(observer);
        mKeyToLifecycleContainers.put(key, lifecycleContainer);

        return new ActivityResultLauncher<I>() {
            @Override
            public void launch(I input, @Nullable ActivityOptionsCompat options) {
                Integer innerCode = mKeyToRc.get(key);
                if (innerCode == null) {
                    throw new IllegalStateException("Attempting to launch an unregistered "
                            + "ActivityResultLauncher with contract " + contract + " and input "
                            + input + ". You must ensure the ActivityResultLauncher is registered "
                            + "before calling launch().");
                }
                mLaunchedKeys.add(key);
                try {
                    onLaunch(innerCode, contract, input, options);
                } catch (Exception e) {
                    mLaunchedKeys.remove(key);
                    throw e;
                }
            }

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

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

其中,下方代码就说明了官方文档的那句

registerForActivityResult() must be called unconditionally, as part of initialization path, typically as a field initializer of an Activity or Fragment.

if (lifecycle.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
            throw new IllegalStateException("LifecycleOwner " + lifecycleOwner + " is "
                    + "attempting to register while current state is "
                    + lifecycle.getCurrentState() + ". LifecycleOwners must call register before "
                    + "they are STARTED.");
        }

即,registerForActivityResult()需要在Activity的状态是STARTED之前被调用。也就是,在定义ActivityResultLauncher变量时,或者在构造函数里,或者在onCreate()/onStart()方法里。