Kotlin 协程 - 优雅地处理挂起函数中的错误

App*_*per 6 error-handling android try-catch kotlin kotlin-coroutines

尝试使用从异步方法调用的挂起函数来实现对错误的优雅处理,如何捕获挂起方法引发的错误。

suspend fun findById(id: Long): User? {
    throw Exception("my exception") // intentionally throwing to simulate error situation.
    return userModel.findById(id) // IO, may throw an error
}
Run Code Online (Sandbox Code Playgroud)

调用者部分,通过 IO 线程启动

GlobalScope.launch(Dispatchers.IO) {
    try {

        var userAsync: Deferred<User?>? = null
        arguments?.getLong("id")?.let {
            userAsync = async { viewModel?.findById(it) } // async for efficiency as i've other async methods too.
        }

        val data = userAsync?.await()

        withContext(Dispatchers.Main) {
            user = data // data binding, populating UI fields of user
        }
    } catch (exception: Exception) {
        withContext(Dispatchers.Main) { fault(exception) }
    }
}
Run Code Online (Sandbox Code Playgroud)

故障方法

private fun fault(exception: Exception) {
    Log.d("User", "fault: ${exception.localizedMessage}") // expecting output
}
Run Code Online (Sandbox Code Playgroud)

当前运行时正在崩溃,希望实现错误的优雅处理。


尝试2

尝试将 try catch 放在异步块中,但它不喜欢它。

var userAsync: Deferred<UserVO?>? = null
arguments?.getLong("id")?.let {
    userAsync = async {
        try {
            delegate?.findById(it)
        } catch (e: Exception) {
            print(e)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Nic*_*zzi 9

我会使用 aCoroutineExceptionHandler让你的协程优雅地失败:

1) 定义处理程序:

val exceptionHandler = CoroutineExceptionHandler { context, error ->
    // Do what you want with the error
    Log.d(TAG, error)
}
Run Code Online (Sandbox Code Playgroud)

2) 重构您的 findById 函数以在 IO 上下文中执行,并使您的 ui 代码主要安全:

suspend fun findById(id : Int) : User? = withContext(Dispatchers.IO){
    when(id){
        0 -> throw Exception("not valid")
        else -> return@withContext User(id)
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 在其中启动您的作业MainScope(并更新 ui),传递 exceptionHandler 来启动协程构建器以捕获异常:
val exceptionHandler = CoroutineExceptionHandler { _, error ->
     // Do what you want with the error
    Log.d(TAG, error)
}

MainScope().launch(exceptionHandler) {
     val user = delegate?.findById(userId)
        user?.let {
            Timber.v(it.toString())
        }
}
Run Code Online (Sandbox Code Playgroud)