【问题标题】:Catch an Exception inside Kotlin callbackFlow builder在 Kotlin 回调流构建器中捕获异常
【发布时间】:2021-02-01 23:12:54
【问题描述】:

我有一个看起来像这样的消费者:

// ItemConsumer.kt
try {
    job = itemService
            .connect()
            .flowOn(Dispatchers.IO)
            .catch { e ->
                throw e
            }
            .onEach {
                // Update UI for each item collected
            }
            .launchIn(viewModelScope)
} catch (e : Exception) {
    // Handle exception
}

我有一个看起来像这样的制作人:

// ItemService.kt (Producer)
fun connect():Flow<Item> = callbackFlow {
    check(1 == 0) // This is expected to throw an IllegalStateException
}

我了解 .catch { } 将处理消费者的 .collect { } 或 .onEach { } 块内出现的任何问题。但是如何抛出 callbackFlow { } 构建器内部发生的异常,以便它可以在消费者的 .catch { } 中捕获?

【问题讨论】:

    标签: kotlin kotlin-coroutines kotlin-flow


    【解决方案1】:

    catch 运算符catches only upstream exceptions (that is an exception from all the operators above catch, but not below it)。在您的代码中,onEach 或 collect(通过 launchIn)中的任何异常都不会被捕获。您需要将此运算符移动到onEach 下方以捕获所有异常。

    此运算符catches exceptions in the flow completion。只有当流程正常或异常完成时,才有可能在callbackFlow builder 中捕获它们。正如@SomeRandomITBoy 所说,它永远不会被流程构建器抛出。但是由于此构建器在后台使用Channel,因此为了异常完成流程,您必须手动close 它具有非空原因:

    abstract fun close(cause: Throwable? = null): Boolean
    

    请记住,这可能会违反透明度:“流程必须对异常透明,并且在 flow { ... } 构建器中从 try/catch 内部发出值违反了异常透明度堵塞”。我可能错了,但我认为,由于您使用catch,因此“保留了这种异常透明度并允许封装其异常处理”。

    所以消费者可能如下:

    job = itemService.connect()
        .flowOn(Dispatchers.IO)
        .onEach {
            // update UI
        }
        .catch { e ->
            // handle exception
        }
        .launchIn(viewModelScope)
    

    并且生产者应该以这样的异常关闭:

    fun connect(): Flow<Item> = callbackFlow {
        try {
            check(1 == 0) // throws an exception
        } catch (e: Exception) {
            close(e) // close manually with exception
        }
    }
    

    【讨论】:

      【解决方案2】:

      你不能。流构建器函数永远不会抛出异常。 Flows 是冷的,这意味着在调用 collect 之前不会执行任何代码。即使集合的执行产生异常,您也将始终成功构建流程。

      【讨论】:

        猜你喜欢
        • 2020-09-25
        • 1970-01-01
        • 2011-03-25
        • 1970-01-01
        • 1970-01-01
        • 2021-12-31
        • 1970-01-01
        • 1970-01-01
        • 2012-02-03
        相关资源
        最近更新 更多