Làm thế nào để gọi yêu cầu không đồng bộ một cách đồng bộ với một giá trị thời gian chờ?
Tôi phải gọi đồng bộ một yêu cầu api không đồng bộ. Vì yêu cầu api này mất nhiều thời gian để trả lời, tôi cũng muốn đặt thời gian chờ để yêu cầu api không thành công và tiếp tục với null. Đây là mã của tôi để gọi api này:
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()
}
}
}
Tôi không thể thay đổi cách thức External3rdPartyApi
hoạt động.
Tôi nghĩ rằng đoạn mã trên trông có vẻ ác. Ngoài ra, tôi đã đọc trong một câu trả lời khác :
withTimeout { ... }
được thiết kế để hủy hoạt động đang diễn ra khi hết thời gian chờ, điều này chỉ có thể thực hiện được nếu hoạt động được đề cập có thể hủy được .
Vì vậy, tôi có nên sử dụng suspendCancellableCoroutine
thay vì suspendCoroutine
?
Làm thế nào tôi có thể viết nó theo cách tốt hơn?
Trả lời
Việc sử dụng suspendCoroutine
cũng được nếu bạn không thể (hoặc không muốn) xử lý việc hủy Đăng ký. Nhưng vì bạn có thời gian chờ, bạn nên cân nhắc sử dụng pauseCancellableCoroutine và xử lý sự kiện hủy để dừng công việc (trong chức năng của bên thứ ba - nếu bạn có thể).
suspendCancellableCoroutine<T> { continuation ->
continuation.invokeOnCancellation { throwable ->
// now you could stop your (third party) work
}
}
Khi hàm bên thứ ba của bạn ném ra một ngoại lệ, bạn có thể thử bắt nó và hoàn thành việc tiếp tục bằng cách tiếp tục với exception
hoặc trả về một null
giá trị (tùy thuộc vào trường hợp sử dụng của bạn):
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)
}
}
Hãy tập hợp tất cả lại với nhau
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
}
}
}
}