#android #kotlin #asynchronous
#Android #котлин #асинхронный
Вопрос:
Мне интересно, почему с помощью следующего кода исключение не перехвачено:
private inline fun <reified T : Any> parseResponse(
httpConnection: HttpURLConnection,
noinline callback: ResponseBlock<T>?
) {
with(httpConnection) {
var error: Throwable? = null
val model = try {
if (this.responseCode in 200..299) {
jacksonObjectMapper().readValue(
this.inputStream.bufferedReader().readText(),
T::class.java
)
} else {
null
}
} catch (e: Exception) {
error = e
null
}
if (model == null amp;amp; error == null) {
error = try {
if (this.responseCode !in 200..299) {
val errorResponse = this.errorStream.bufferedReader().readText()
Throwable(errorResponse)
} else {
null
}
} catch (e: Exception) {
e
}
}
error?.let {
Log.e(this::class.simpleName, it.message, it)
}
callback?.invoke(this.responseCode, model, error)
this.disconnect()
}
}
Функция вызывается следующим образом:
private inline fun <reified T : Any> get(
pathComponents: Array<String>,
noinline callback: ResponseBlock<T>?,
queryParameters: Map<String, Any>? = null
) {
thread(start = true) {
val urlRequest = createUrlRequest(HttpMethod.GET, pathComponents, queryParameters)
parseResponse(urlRequest, callback)
}
}
И все же я получаю это исключение, которое приводит к сбою приложения:
E/HttpURLConnectionImpl: Failed to connect to /10.0.2.2:8080
java.net.ConnectException: Failed to connect to /10.0.2.2:8080
at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:147)
at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116)
at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186)
at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128)
at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:411)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:542)
at io.openremote.app.network.ApiManager$getAppConfig$inlined$get$1.invoke(ApiManager.kt:148)
at io.openremote.app.network.ApiManager$getAppConfig$inlined$get$1.invoke(ApiManager.kt:14)
at kotlin.concurrent.ThreadsKt$thread$thread$1.run(Thread.kt:30)
E/AndroidRuntime: FATAL EXCEPTION: Thread-2
Process: io.openremote.app, PID: 3901
java.net.ConnectException: Failed to connect to /10.0.2.2:8080
at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:147)
at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116)
at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186)
at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128)
at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:411)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:542)
at io.openremote.app.network.ApiManager$getAppConfig$inlined$get$1.invoke(ApiManager.kt:148)
at io.openremote.app.network.ApiManager$getAppConfig$inlined$get$1.invoke(ApiManager.kt:14)
at kotlin.concurrent.ThreadsKt$thread$thread$1.run(Thread.kt:30)
Я бы сказал, что блоки try / catch перехватят исключение, но, увы…
Что приводит к тому, что исключение не перехвачено? Я бы сказал, что многопоточность не имеет значения, потому что я использую блоки try / catch для обработки исключений в потоке.
Обновить
После ответа Лаалто я обновил код, чтобы он выглядел следующим образом (для тех, кто заинтересован):
private inline fun <reified T : Any> parseResponse(
httpConnection: HttpURLConnection,
noinline callback: ResponseBlock<T>?
) {
with(httpConnection) {
val parsedResult = try {
if (this.responseCode in 200..299) {
Triple(
this.responseCode, jacksonObjectMapper().readValue(
this.inputStream.bufferedReader().readText(),
T::class.java
), null
)
} else {
val errorResponse = this.errorStream.bufferedReader().readText()
Triple(this.responseCode, null, Throwable(errorResponse))
}
} catch (e: Exception) {
Triple(0, null, e)
}
parsedResult.third?.let {
Log.e(this::class.simpleName, it.message, it)
}
callback?.invoke(parsedResult.first, parsedResult.second, parsedResult.third)
this.disconnect()
}
}
Комментарии:
1. В конце у вас есть доступ к
responseCode
без try-catch:callback?.invoke(this.responseCode, model, error)
2. Ты прав, Лаалто. Если вы добавили его в качестве ответа, я приму его как правильный ответ.
Ответ №1:
Трассировка стека показывает исключение, пытающееся вызвать getResponseCode()
. В конце есть один доступ к responseCode
без try
— catch
block:
callback?.invoke(this.responseCode, model, error)
Более ранние блоки catch работают просто отлично, но код продолжает выполнять эту часть, которая затем выдает исключение.
Как и в вашем обновленном вопросе, вы уже реструктурировали код вокруг этой проблемы.