I am trying to create a Kotlin wrapper on Java Thread based API and I can come up with two approaches, so needs some suggestions in terms of choosing one.
Let’s say I have a Java API which performs an async operation in a thread and returns result via callback as below. For simplicity and example perspective, it is written in Kotlin right now but assume that it is in Java.
// Assume that this class is thread safe.
class Operation {
fun cancel() {
// Cancel the long running operation
}
fun execute(onSuccess: (Int) -> Unit, onFailure: (Exception) -> Unit) {
thread(name = "suspend") {
sleep(1000)
onSuccess(50)
}
}
}
Now to create a wrapper over it which can be suspended, I can think of below two approaches:
1. With Completable Deferred
suspend fun awaitResult(): Int = coroutineScope {
val deferred = CompletableDeferred<Int>(this.coroutineContext[Job])
val operation = Operation()
operation.execute(
onSuccess = {
deferred.complete(it)
},
onFailure = {
deferred.completeExceptionally(it)
}
)
try {
deferred.await()
} catch (e: CancellationException) {
operation.cancel()
throw e
}
}
2. With Suspend Coroutine
suspend fun awaitResult(): Int = suspendCancellableCoroutine { continuation ->
val operation = Operation()
continuation.invokeOnCancellation {
operation.cancel()
}
operation.execute(
onSuccess = {
continuation.resume(it)
},
onFailure = {
continuation.resumeWithException(it)
}
)
}
It seems both are working as expected. Though internally for some of the suspend functions, kotlin itself is using suspendCancellableCoroutine
and Retrofit is also using it to give support for suspend functions for services. So I think I am missing something here and would love to hear the difference and suggestion.
Also in one of the thread I have read that Continuation is an internal implementation detail and should not be used outside, does that still hold true?