startActivityForResult的替代方法:registerForActivityResult

QuibblerQuibbler 2023-07-28 约 14 分钟 2711 次阅读

startActivityForResult的替代方法:registerForActivityResult

在startActivityForResult的用法一文的最后提到startActivityForResult方法已经废弃,推荐使用AndroidX中的registerForActivityResult方法。

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

将ActivityResultCallback注册到ActivityResultRegistry中:

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

1、registerForActivityResult

以注册获取启动Activity返回的结果为例,这里借助ActivityResultContracts,提供了丰富的实现,只需要通过其中的StartActivityForResult()方法即可获取ActivityResultContract<Intent, ActivityResult>:

val register:ActivityResultContract<Intent, ActivityResult> = ActivityResultContracts.StartActivityForResult()

然后再重写ActivityResultCallback接口:

val callback = object : ActivityResultCallback<ActivityResult> {
	override fun onActivityResult(result: ActivityResult?) {
		Log.d("TAG", "resultCode:${result?.resultCode}  data:${result?.data}")
	}
    }

用前面提到的registerForActivityResult()方法将两者注册:

registerForActivityResult(register, callback)

会获得返回的ActivityResultLauncher对象:

val launcher: ActivityResultLauncher<Intent> = registerForActivityResult(register, callback)

通过该ActivityResultLauncher可以启动我们的Activity:

val intent = Intent()
    //
    
    launcher.launch(intent)

看到这里它的优势相比也显而易见,将繁杂的注册和结果回调解耦,不用全部集中在Activity的一个onActivityResult()回调方法中。且每种不同的业务启动不同的Activity,都可以有自己独立的launcher和处理回调。

2、各种ActivityResultContract

Android开发中除了获取启动Activity返回的结果,申请权限的回调。还有非常多的场景,可以通过实现ActivityResultContract<I,O>完成不同场景下的启动:

abstract class ActivityResultContract<I, O> {
	/**
	 * Create an intent that can be used for [android.app.Activity.startActivityForResult].
	 */
	abstract fun createIntent(context: Context, input: I): Intent
	
	/**
	 * Convert result obtained from [android.app.Activity.onActivityResult] to [O].
	 */
	abstract fun parseResult(resultCode: Int, intent: Intent?): O
	
	/**
	 * An optional method you can implement that can be used to potentially provide a result in
	 * lieu of starting an activity.
	 *
	 * @return the result wrapped in a [SynchronousResult] or `null` if the call
	 * should proceed to start an activity.
	 */
	open fun getSynchronousResult(context: Context, input: I): SynchronousResult<O>? {
		return null
	}
	
	/**
	 * The wrapper for a result provided in [getSynchronousResult]. This allows differentiating
	 * between a null [T] synchronous result and no synchronous result at all.
	 */
	class SynchronousResult<T>(val value: T)
    }

而且ActivityResultContracts也提供了非常多现成的实现,比如启动文件选择、获取照片选择结果、启动相机拍照获取结果等等。


3、registerForActivityResult原理

前面了解了startActivityForResult的原理,registerForActivityResult其实也一样,它的注册流程如下:

通过返回的ActivityResultLauncher启动Activity流程:

接着startActivityForResult的原理一文,我们知道结果回调。这里AndroidX库中的ComponentActivity重写了onActivityResult()回调方法:

@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (!mActivityResultRegistry.dispatchResult(requestCode, resultCode, data)) {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

通过前面注册的mActivityResultRegistry分发处理这次回调结果,如果没有被处理,还是走原来的处理onActivityResult()回调逻辑。

@MainThread
    public final boolean dispatchResult(int requestCode, int resultCode, @Nullable Intent data) {
        String key = mRcToKey.get(requestCode);
        if (key == null) {
            return false;
        }
        doDispatch(key, resultCode, data, mKeyToCallback.get(key));
        return true;
    }

紧接着调用doDispatch()方法处理分发结果:

private <O> void doDispatch(String key, int resultCode, @Nullable Intent data,
            @Nullable CallbackAndContract<O> callbackAndContract) {
        if (callbackAndContract != null && callbackAndContract.mCallback != null
                && mLaunchedKeys.contains(key)) {
            ActivityResultCallback<O> callback = callbackAndContract.mCallback;
            ActivityResultContract<?, O> contract = callbackAndContract.mContract;
            callback.onActivityResult(contract.parseResult(resultCode, data));
            mLaunchedKeys.remove(key);
        } else {
            // Remove any parsed pending result
            mParsedPendingResults.remove(key);
            // And add these pending results in their place
            mPendingResults.putParcelable(key, new ActivityResult(resultCode, data));
        }
    }

最终是在我们注册的ActivityResultCallback回调中处理onActivityResult结果:

/**
	* A type-safe callback to be called when an {@link Activity#onActivityResult activity result}
	* is available.
	*
	* @param <O> result type
    */
    public interface ActivityResultCallback<O> {
	/**
	 * Called when result is available
		*/
	void onActivityResult(@SuppressLint("UnknownNullness") O result);
    }

上面整体的流程是:

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w