简体   繁体   English

Kotlin Coroutines Flow catch 机制

[英]Kotlin Coroutines Flow catch mechanism

In my sample I'm calling.network operation and emitting success case but on error eg 404 app crashes wihout emitting exception.在我的示例中,我正在调用.network 操作并发出成功案例,但出现错误,例如 404 应用程序崩溃而没有发出异常。 Surrendering with try catch prevent crashes but I want to pass error till the ui layer like success case.使用 try catch 投降可以防止崩溃,但我想像成功案例一样将错误传递到 ui 层。

  suspend fun execute(
    params: Params,
):
        Flow<Result<Type>> = withContext(Dispatchers.IO) {
    flow {
        emit(Result.success(run(params)))
    }.catch {
        emit(Result.failure(it))
    }

}

If you want to use flows you can use the catch method of flows.如果你想使用流,你可以使用流的catch方法。 As you said you can use try-catch but it would break the structured concurrency since it would catch the cancellation exception as well or it would avoid the cancellation exception to be thrown.正如您所说,您可以使用try-catch但它会破坏结构化并发,因为它也会捕获取消异常或者它会避免抛出取消异常。 One thing that you can do is to use an Exception handler at the point where you launch the root coroutine that calls the suspend function.您可以做的一件事是在启动调用suspend function 的协程时使用异常处理程序。

val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception -> 
    // handle it
}

scope.launch(handler) { // root coroutine
    execute(params)
    somethingThatShouldBeExecutedOnlyIfPreviousCallDoesNotThrow()
}

This solution is good for both flows and non-flow coroutines.该解决方案适用于流和非流协程。

In the solution with the runCatching you will have to manually check the result of the first execute to avoid the second one to run.在带有runCatching的解决方案中,您必须手动检查第一次执行的结果以避免第二次运行。 One interesting thread is here .这里有一个有趣的线程。

There is a helpful function runCatching for creating a Result easily, but the problem in coroutines is that you don't want to be swallowing CancellationExceptions.有一个有用的 function runCatching可以轻松创建结果,但协程中的问题是您不想吞下 CancellationExceptions。 So below, I'm using runCatchingCancellable from my answer here .所以在下面,我在此处的回答中使用runCatchingCancellable

This shouldn't be a Flow since it returns a single item.这不应该是 Flow,因为它返回单个项目。

If run is a not a blocking function (it shouldn't be if you are using Retrofit with suspend functions), your code can simply be:如果run不是阻塞 function(如果您使用带有挂起函数的 Retrofit 则不应该是),您的代码可以简单地是:

suspend fun execute(params: Params): Result<Type> = runCatchingCancellable {
    run(params)
}

If it is a blocking function you can use:如果它是一个阻塞 function 你可以使用:

suspend fun execute(params: Params): Result<Type> = runCatchingCancellable {
    withContext(Dispatchers.IO) {
        run(params)
    }
}

If you were going to return a Flow (which you shouldn't for a returning a single item,!), then you shouldn't make this a suspend function, and you should catch the error inside the flow builder lambda:如果您要返回一个流程(您应该返回一个项目,!),那么您不应该将其设为suspend function,并且您应该flow构建器 lambda 中捕获错误:

fun execute(params: Params): Flow<Result<Type>> = flow {
    emit(runCatchingCancellable {
        run(params)
    })
}

// or if run is blocking (it shouldn't be):

fun execute(params: Params): Flow<Result<Type>> = flow {
    emit(runCatchingCancellable {
        withContext(Dispatchers.IO) { run(params) }
    })
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM