From 86048ee1fd4405c80089a1d81c297384ad4a4337 Mon Sep 17 00:00:00 2001 From: atsunatsu Date: Tue, 8 Sep 2026 04:32:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(lotw):=20run=20report=20fetch=20on=20Dispat?= =?UTF-8?q?chers.IO=20=E2=80=94=20main-thread=20blocking=20caused=20ANR/cr?= =?UTF-8?q?ash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fetchReportBody is a synchronous HttpURLConnection call (up to 30s connect + 120s read) but was invoked directly from a Main-dispatcher viewModelScope coroutine: the whole UI froze for the duration of the request, then Android killed the app with an ANR dialog. Wrap both fetch methods in withContext(Dispatchers.IO). Bug present since the endpoint was introduced. --- .../core/data/repository/LoTWRepository.kt | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/LoTWRepository.kt b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/LoTWRepository.kt index 36e7d5b2..00209144 100644 --- a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/LoTWRepository.kt +++ b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/LoTWRepository.kt @@ -45,20 +45,24 @@ import javax.net.ssl.SSLException class LoTWRepository : ILoTWRepository { override suspend fun fetchConfirmedGrids(callsign: String, password: String): LoTWResult = + withContext(Dispatchers.IO) { + fetchReportBody(callsign, password).fold( + onSuccess = { body -> parseBoth(body)?.let { LoTWResult.Success(it.first, it.second) } + ?: LoTWResult.RateLimited }, + onFailure = { toResult(it) } + ) + } + + override suspend fun fetchConfirmedGridQsos( + callsign: String, + password: String + ): LoTWResult = withContext(Dispatchers.IO) { fetchReportBody(callsign, password).fold( onSuccess = { body -> parseBoth(body)?.let { LoTWResult.Success(it.first, it.second) } ?: LoTWResult.RateLimited }, onFailure = { toResult(it) } ) - - override suspend fun fetchConfirmedGridQsos( - callsign: String, - password: String - ): LoTWResult = fetchReportBody(callsign, password).fold( - onSuccess = { body -> parseBoth(body)?.let { LoTWResult.Success(it.first, it.second) } - ?: LoTWResult.RateLimited }, - onFailure = { toResult(it) } - ) + } internal fun toResult(e: Throwable): LoTWResult = when (e) { is CredentialsException -> LoTWResult.BadCredentials