onActivityResult已废弃,快来看看更好用的Activity Result API

大家更新了SDK后,应该都发现了之前用的很多的startActivityForResult和onActivityResult方法已经声明已废弃了,在查看源码后,我们可以看到onActivityResult方法上声明了@Deprecated,建议我们使用Activity Result API来代替

/**
 * {@inheritDoc}
 *
 * @deprecated This method has been deprecated in favor of using the Activity Result API
 * which brings increased type safety via an {@link ActivityResultContract} and the prebuilt
 * contracts for common intents available in
 * {@link androidx.activity.result.contract.ActivityResultContracts}, provides hooks for
 * testing, and allow receiving results in separate, testable classes independent from your
 * activity. 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);
}
/**
 * {@inheritDoc}
 *
 * @deprecated This method has been deprecated in favor of using the Activity Result API
 * which brings increased type safety via an {@link ActivityResultContract} and the prebuilt
 * contracts for common intents available in
 * {@link androidx.activity.result.contract.ActivityResultContracts}, provides hooks for
 * testing, and allow receiving results in separate, testable classes independent from your
 * activity. 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);
    }
}

我们可以直接使用registerForActivityResult来代替startActivityForResult

lateinit var activityResultLauncher: ActivityResultLauncher

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        // 处理回调
    }
    // 跳转页面
    activityResultLauncher.launch(Intent(this, SecondActivity::class.java))
}

但是这种方法有个弊端,如果我们有多个页面跳转的话,我们无法在同一个activityResultLauncher的回调中判断是来自哪一个的回调,因为缺少了requestCode,这时候我们只能通过注册多个来解决这个问题,这样不是比之前更麻烦了么,有没有更好的办法呢?

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

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

我们继续看源码发现,registerForActivityResult其实是调用ActivityResultRegistry来注册的,而ActivityResultRegistry我们是可以直接获取到的,我们可以自己封装一下

private val requestCode = AtomicInteger()
private val key: String get() = "activity_rq#${requestCode.getAndIncrement()}"
val activityContracts = ActivityResultContracts.StartActivityForResult()

suspend fun  ComponentActivity.launch(
    contract: ActivityResultContract,
    input: I
): O {
    var caller: ActivityResultLauncher? = null
    return suspendCancellableCoroutine { continuation ->
        caller = activityResultRegistry.register(key, contract) {
            continuation.resume(it)
        }.apply {
            launch(input)
        }
    }.also {
        caller?.unregister()
        caller = null
    }
}

fun  ComponentActivity.launch(
    contract: ActivityResultContract,
    input: I,
    output: ActivityResultCallback
) {
    var caller: ActivityResultLauncher? = null
    caller = activityResultRegistry.register(key, contract) {
        output.onActivityResult(it)
        caller?.unregister()
        caller = null
    }.apply {
        launch(input)
    }
}

/**
 * 启动activity获取返回值
 */
fun ComponentActivity.launchActivityForResult(
    intent: Intent,
    output: ActivityResultCallback
) = launch(activityContracts, intent, output)

使用方法如下

// 正常使用
launchActivityForResult(Intent(this, SecondActivity::class.java)) {
    // 处理回调
}
// 在协程中使用
lifecycleScope.launch {
    val activityResult = launch(
        contract = activityContracts,
        input = Intent(this@MainActivity, SecondActivity::class.java)
    )
    // 处理回调
}

看起来是不是简洁很多了,而且代码逻辑也清晰不少。

ActivityResultContracts中,除了StartActivityForResult外,还内置了一些常用的

页面更新:2024-04-01

标签:上声   弊端   文件夹   简洁   源码   逻辑   权限   页面   文件   方法

1 2 3 4 5

上滑加载更多 ↓
Top