시간 제한 값을 사용하여 비동기 요청을 동기식으로 호출하는 방법은 무엇입니까?
Jan 07 2021
비동기 API 요청을 동 기적으로 호출해야합니다. 이 API 요청은 응답하는 데 오랜 시간이 걸리기 때문에 api 요청을 실패하고 null로 계속하는 시간 제한도 설정하고 싶습니다. 이 API를 호출하는 코드는 다음과 같습니다.
private suspend fun call(
accessStage: AccessStage,
): Response? = withContext<Response?>(Dispatchers.IO) {
return@withContext withTimeoutOrNull(1000) {
suspendCoroutine<Response?> { continuation ->
val request = External3rdPartyApi.newRequest(
accessStage
) { response, throwable ->
continuation.resume(response)
}
request.parameters = hashMapOf<String, String>().apply {
put["token"] = External3rdPartyApi.TOKEN
put["salt"] = External3rdPartyApi.calculateSalt(accessStage)
}
request.executeAsync()
}
}
}
External3rdPartyApi
작동 방식을 변경할 수 없습니다 .
위의 코드가 나쁘다고 생각합니다. 또한 다른 답변을 읽었습니다 .
withTimeout { ... }
시간 초과시 진행중인 작업을 취소하도록 설계되었으며 이는 해당 작업을 취소 할 수있는 경우에만 가능합니다 .
그래서 suspendCancellableCoroutine
대신 사용해야 suspendCoroutine
합니까?
더 나은 방법으로 작성하려면 어떻게해야합니까?
답변
1 ChristianB Jan 07 2021 at 19:42
코 suspendCoroutine
루틴 취소를 처리 할 수 없거나 원하지 않는 경우 사용하는 것이 좋습니다. 그러나 시간 초과가 있기 때문에 suspendCancellableCoroutine 사용을 고려 하고 취소 이벤트를 처리하여 작업을 중지해야합니다 (가능한 경우 타사 함수에서).
suspendCancellableCoroutine<T> { continuation ->
continuation.invokeOnCancellation { throwable ->
// now you could stop your (third party) work
}
}
제 3 자 함수가 예외를 던질 때, 당신은 그것을 try-catch exception
하고 null
값으로 재개 하거나 값을 반환 (사용 사례에 따라 다름) 사용하여 계속을 완료 할 수 있습니다.
suspendCancellableCoroutine<T?> { continuation ->
try {
continuation.resume(thirdParty.call())
} catch (e: Exception) {
// resume with exception
continuation.resumeWithException(e)
// or just return null and swallow the exception
continuation.resume(null)
}
}
모두 합치 자
suspend fun call(): Response? = withContext(Dispatchers.IO) {
return@withContext withTimeoutOrNull(1000L) {
return@withTimeoutOrNull suspendCancellableCoroutine { continuation ->
try {
continuation.resume(External3rdPartyApi.newRequest(accessStage))
} catch (e: Exception) {
// resume with exception
continuation.resumeWithException(e)
// or just return null and swallow the exception
continuation.resume(null)
}
// in case the coroutine gets cancelled - because of timeout or something else
continuation.invokeOnCancellation {
// stop all the work
}
}
}
}