Kotlin 协同程序崩溃,没有有用的堆栈跟踪
Kotlin coroutines crash with no helpful stacktrace
我的 Android 应用程序崩溃了,我在 Logcat 中看到了这个堆栈跟踪。它没有告诉我是哪一行代码导致了问题。
2021-05-05 09:13:33.143 1069-1069/com.mycompany.app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mycompany.app, PID: 1069
retrofit2.HttpException: HTTP 403
at retrofit2.KotlinExtensions$await.onResponse(KotlinExtensions.kt:53)
at retrofit2.OkHttpCall.onResponse(OkHttpCall.java:161)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
有没有办法将其映射回我的代码,以查看是哪个改造调用导致的?我有一个包含如下代码的存储库:
suspend fun getSomeData(): Stuff {
return withContext(Dispatchers.IO) {
val body = myRetroApi.getStuff()
...
我是否需要包装每个 withContext
body 以确保没有 Throwables
逃逸?我认为如果有什么东西在那里抛出异常,它会记录一个错误,而不是让整个应用程序崩溃。
编辑
我问这个问题的时候搞砸了,把重点放在了错误的地方。所以我要删除“改造”标签。事实证明 withContext(Dispatchers.IO)
调用按预期执行 re-throw Exception
,但是当异常返回到 viewModelScope.launch
时,如果该块没有捕获它,应用程序会崩溃.
如果不处理异常,应用程序当然会崩溃。
您可以添加一个 try catch 来避免这种情况:
suspend fun getSomeData() {
withContext(Dispatchers.IO) {
try{
val body = myRetroApi.getStuff()
...
} catch (e : Exception){
//your code
}
...
Retrofit 给您一个 403 Unauthorized HTTP 异常。可能是服务器未传递任何其他错误消息,或者您需要捕获 HttpException 并检查消息。在任何一种情况下,这都不是 Retrofit 问题,因此它只是传递从您调用的服务器获得的错误。
最好为 API 调用创建一个网络结果包装器和一个包装器函数来处理异常。
你可以这样做。请记住,实际实施完全取决于您。但是,我建议在协程中使用 runCatching,因为它可以处理取消异常。
sealed class NetworkResult<out T> {
data class Success<T>(val data: T) : NetworkResult<T>()
data class Error(val exception: Throwable, val message: String?) : NetworkResult<Nothing>()
}
suspend fun networkCall(): String = ""
suspend fun <T> safeApiCall(block: suspend () -> T): NetworkResult<T> {
return runCatching {
withContext(Dispatchers.IO) {
block()
}
}.fold({
NetworkResult.Success(it)
}, {
when (it) {
is HttpException -> NetworkResult.Error(it, "Network error")
else -> NetworkResult.Error(it, "Some other message...")
// else -> throw it
}
})
}
suspend fun getData() {
val result: NetworkResult<String> = safeApiCall {
networkCall()
}
when (result) {
is NetworkResult.Success -> {
//Handle success
}
is NetworkResult.Error -> { //Handle error
}
}
}
runCatching 使用 Kotlin 的内置结果 class 并且有多种处理结果的方法。这些只是一小部分。
runCatching {
//.....
}.getOrElse { throwable ->
//handle exception
}
runCatching {
//.....
}.getOrThrow()
runCatching {
}.onSuccess {
}.onFailure {
}
我的 Android 应用程序崩溃了,我在 Logcat 中看到了这个堆栈跟踪。它没有告诉我是哪一行代码导致了问题。
2021-05-05 09:13:33.143 1069-1069/com.mycompany.app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mycompany.app, PID: 1069
retrofit2.HttpException: HTTP 403
at retrofit2.KotlinExtensions$await.onResponse(KotlinExtensions.kt:53)
at retrofit2.OkHttpCall.onResponse(OkHttpCall.java:161)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
有没有办法将其映射回我的代码,以查看是哪个改造调用导致的?我有一个包含如下代码的存储库:
suspend fun getSomeData(): Stuff {
return withContext(Dispatchers.IO) {
val body = myRetroApi.getStuff()
...
我是否需要包装每个 withContext
body 以确保没有 Throwables
逃逸?我认为如果有什么东西在那里抛出异常,它会记录一个错误,而不是让整个应用程序崩溃。
编辑
我问这个问题的时候搞砸了,把重点放在了错误的地方。所以我要删除“改造”标签。事实证明 withContext(Dispatchers.IO)
调用按预期执行 re-throw Exception
,但是当异常返回到 viewModelScope.launch
时,如果该块没有捕获它,应用程序会崩溃.
如果不处理异常,应用程序当然会崩溃。
您可以添加一个 try catch 来避免这种情况:
suspend fun getSomeData() {
withContext(Dispatchers.IO) {
try{
val body = myRetroApi.getStuff()
...
} catch (e : Exception){
//your code
}
...
Retrofit 给您一个 403 Unauthorized HTTP 异常。可能是服务器未传递任何其他错误消息,或者您需要捕获 HttpException 并检查消息。在任何一种情况下,这都不是 Retrofit 问题,因此它只是传递从您调用的服务器获得的错误。
最好为 API 调用创建一个网络结果包装器和一个包装器函数来处理异常。
你可以这样做。请记住,实际实施完全取决于您。但是,我建议在协程中使用 runCatching,因为它可以处理取消异常。
sealed class NetworkResult<out T> {
data class Success<T>(val data: T) : NetworkResult<T>()
data class Error(val exception: Throwable, val message: String?) : NetworkResult<Nothing>()
}
suspend fun networkCall(): String = ""
suspend fun <T> safeApiCall(block: suspend () -> T): NetworkResult<T> {
return runCatching {
withContext(Dispatchers.IO) {
block()
}
}.fold({
NetworkResult.Success(it)
}, {
when (it) {
is HttpException -> NetworkResult.Error(it, "Network error")
else -> NetworkResult.Error(it, "Some other message...")
// else -> throw it
}
})
}
suspend fun getData() {
val result: NetworkResult<String> = safeApiCall {
networkCall()
}
when (result) {
is NetworkResult.Success -> {
//Handle success
}
is NetworkResult.Error -> { //Handle error
}
}
}
runCatching 使用 Kotlin 的内置结果 class 并且有多种处理结果的方法。这些只是一小部分。
runCatching {
//.....
}.getOrElse { throwable ->
//handle exception
}
runCatching {
//.....
}.getOrThrow()
runCatching {
}.onSuccess {
}.onFailure {
}