英文:
Propagate exception from background thread to main thread with Kotlin Coroutines
问题
With Kotlin Coroutines,我需要在同一个try
块中同时并行运行两个I/O工作,而不会相互阻塞。如果其中任何一个工作失败,它应该在单个catch
块中捕获。这两个操作是:
a)连续每10秒ping服务器。
b)使用okhttp进行网络调用。
我需要将这两个操作封装在一个suspend
函数中。
以下是代码示例:
suspend fun sendAllRequests() {
try {
val pingJob = GlobalScope.launch { pingServer() }
val networkCallJob = GlobalScope.launch { makeNetworkCall() }
// 等待两个任务完成
pingJob.join()
networkCallJob.join()
} catch (exception: CustomException) {
// 处理异常
throw RuntimeException("Custom Error")
}
}
suspend fun pingServer() {
while (true) {
delay(10000)
if (isPingSuccess) {
Log.d("Connection active")
} else {
Log.d("Connection Inactive")
throw RuntimeException("Ping failed")
}
}
}
suspend fun makeNetworkCall() {
// 这是一个伪代码,仅用于说明
try {
okhttp.newCall().await()
} catch (e: Exception) {
// 处理网络调用异常
throw CustomException("Network call failed", e)
}
}
通过上述代码,你可以并行运行这两个长时间运行的任务,同时捕获它们抛出的异常,并在catch
块中处理它们。不会相互阻塞。
英文:
With Kotlin Coroutines I need to run two I/O work inside a try
block at same time parallely without blocking each other.
And if any of the work fails, then it should be caught inside a single catch
block.
Two operations are:
a) Continuously ping the server at a 10 second interval.
b) Make a network call with okhttp.
I need to cover these two operations inside a suspend
function.
PSB code:
suspend fun sendAllRequests() {
try {
pingServer()
makeNetworkCall()
} catch(exception: CustomException) {
// Do some other work and throw exception to UI
throw RuntimeException("Custom Error")
}
}
suspend fun pingServer() {
job = GlobalScope.launch {
while(true) {
delay(10000) {
if(isPingSuccess) {
Log("Connection active")
} else {
Log("Connection Inactive")
job.cancel()
throw RuntimeException("Ping failed")
}
}
}
}
suspend fun makeNetworkCall() {
//This is a pseudo code just for explanation
okhttp.newCall().await()
onFailure -> throw Exception
}
The challenge with above approach is that it, only initiates the logic present inside function pingServer()
.
i.e. The function makeNetworkCall()
is never triggered.
And if I wrap the first function inside a new coroutine scope like below:
then both job works fine, but the exception thrown by pingServer()
is never caught in catch
block.
try {
// With below logic, both functions are triggered
scope.launch { pingServer() }
makeNetworkCall()
} catch {
// but pingServer() failure never reaches here
// and makeNetworkCall() failure is properly captured here
}
How can I run the above two long running tasks parallely without blocking each other ?
How can I ensure that if any of them throws an exception, then it is caught inside the same catch
block as shown above ?
答案1
得分: 1
根据这篇文章,实现你想要的方法的一个简单方式是不使用 launch
,而是使用 async
。然后,你可以运行你的 makeNetworkCall()
,然后在你的异步延迟对象上使用 await
来捕获异常。
类似这样的代码:
suspend fun sendAllRequests() {
try {
val deferred = GlobalScope.async { pingServer() }
makeNetworkCall()
deferred.await()
} catch(exception: CustomException) {
// Do some other work and throw exception to UI
throw RuntimeException("Custom Error")
}
}
请注意以下事项:
- 启动或异步另一个协程并不意味着代码在后台线程上运行,你需要将你的协程启动到另一个调度程序上,例如 Dispatchers.IO。
- 避免使用 GlobalScope,这样做可能会导致内存泄漏。创建自己的作用域,或者如果你在Android上,可以尝试使用应用程序组件作用域,如 viewModelScope 或 lifecycleScope。
英文:
Based on this article, an easy way to achieve what you are after is to not use launch
but use async
.
Then you can run your makeNetworkCall()
and after that await
on your async deferred object catching the exception there
Something like this:
suspend fun sendAllRequests() {
try {
val deferred = GlobalScope.async { pingServer() }
makeNetworkCall()
deferred.await()
} catch(exception: CustomException) {
// Do some other work and throw exception to UI
throw RuntimeException("Custom Error")
}
}
Please also note:
- The fact that you launch or async on another coroutine does not mean that code runs on background thread, you will need to launch your coroutine to another dispatcher for this (eg. Dispatchers.IO)
- Avoid using GlobalScope, you can easily create memory leaks doing so. Create your own scope or if you are on Android, try using the App Components scopes like viewModelScope or lifecycleScope
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论