タイムアウト値と同期して非同期リクエストを呼び出す方法は?
非同期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
suspendCoroutine
コルーチンのキャンセルを処理できない(または処理したくない)場合は、使用しても問題ありません。しかし、あなたがタイムアウトを持っているので、あなたが使用することを検討すべきであるsuspendCancellableCoroutineを( -可能な場合は、サードパーティの機能で)、作業を停止するためにキャンセルイベントを処理します。
suspendCancellableCoroutine<T> { continuation ->
continuation.invokeOnCancellation { throwable ->
// now you could stop your (third party) work
}
}
サードパーティの関数が例外をスローした場合、それをキャッチして、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
}
}
}
}