android - 在协程上下文中返回 Kotlin 结果会引发异常

标签 android kotlin kotlin-coroutines kotlin-android-extensions

我有一个简单的设置:

lifecycleScope.launch {
    val result = test()
}
    
suspend fun test(): Result<Unit> = withContext(Dispatchers.IO)  {
    Result.failure(IllegalStateException("QWER"))
}
实际结果:
上面的代码崩溃了:
java.lang.IllegalStateException:QWER
预期结果:
结果对象按预期返回
我正在使用 kotlin 1.4.10 和协程 1.3.9。我使用 kotlin.Result 对象作为返回类型,因为我有:
kotlinOptions {
    freeCompilerArgs = ["-Xallow-result-return-type"]
}
另一件事是,如果我使用主上下文(Dispatchers.Main)执行协程,一切都会按预期工作。

最佳答案

更新
从 Kotlin 1.5 开始,Result 被用作 Kotlin 函数的直接结果类型。 more details in KEEP

我有同样的崩溃。
这些代码在 Kotlin 为 1.3.72 但在 1.4.0 崩溃时工作。
我的解决方案是复制 kotlin.Result到我的项目。

class Result<out T>(val value: Any?) {

    val isSuccess: Boolean get() = value !is Failure

    val isFailure: Boolean get() = value is Failure

    fun getOrNull(): T? = when {
        isFailure -> null
        else -> value as T
    }

    fun exceptionOrNull(): Throwable? = when (value) {
        is Failure -> value.exception
        else -> null
    }

    override fun toString(): String =
        when (value) {
            is Failure -> value.toString() // "Failure($exception)"
            else -> "Success($value)"
        }

    companion object {
        fun <T> success(value: T): Result<T> = Result(value)

        fun <T> failure(exception: Throwable): Result<T> = Result(createFailure(exception))
    }

    class Failure(val exception: Throwable) {
        override fun equals(other: Any?): Boolean = other is Failure && exception == other.exception
        override fun hashCode(): Int = exception.hashCode()
        override fun toString(): String = "Failure($exception)"
    }
}

private fun createFailure(exception: Throwable): Any = Result.Failure(exception)

inline fun <R, T> Result<T>.fold(
    onSuccess: (value: T) -> R,
    onFailure: (exception: Throwable) -> R
): R {
    return when (val exception = exceptionOrNull()) {
        null -> onSuccess(value as T)
        else -> onFailure(exception)
    }
}

inline fun <R, T> Result<T>.map(transform: (value: T) -> R): Result<R> {
    return when {
        isSuccess -> Result.success(transform(value as T))
        else -> Result(value)
    }
}

inline fun <T> Result<T>.onFailure(action: (exception: Throwable) -> Unit): Result<T> {
    exceptionOrNull()?.let { action(it) }
    return this
}

inline fun <T> Result<T>.onSuccess(action: (value: T) -> Unit): Result<T> {
    if (isSuccess) action(value as T)
    return this
}

fun <T> Result<T>.getOrThrow(): T {
    throwOnFailure()
    return value as T
}

fun Result<*>.throwOnFailure() {
    if (value is Result.Failure) throw value.exception
}

inline fun <R, T : R> Result<T>.getOrElse(onFailure: (exception: Throwable) -> R): R {
    return when (val exception = exceptionOrNull()) {
        null -> value as T
        else -> onFailure(exception)
    }
}

fun <R, T : R> Result<T>.getOrDefault(defaultValue: R): R {
    if (isFailure) return defaultValue
    return value as T
}

关于android - 在协程上下文中返回 Kotlin 结果会引发异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64859624/

相关文章:

android - 初始化后如何修改 Kotlin Coroutine Flow 的值?

android - 如何安全地(生命周期感知).collectAsState() 一个 StateFlow?

android - 如何处理 Firebase Auth account-exists-with-different-credential 错误

Android - EditText 设置前缀始终可见

java - 使用方法引用定义 BroadcastReceiver.onReceive

java - 添加两 Pane 平板电脑布局导致在移动设备中找不到 View (小于 w600dp)

android - 添加 fragment 时更改操作栏项目和标题

java - RecyclerView ListAdapter不显示特定项目

kotlin - 面向多平台时测试方法名称中的空格

kotlin - 如何在不阻塞调用函数的情况下从另一个挂起函数调用挂起函数?