franztesca
02/21/2023, 2:08 PMdownloadSomething(onCompleted: () -> Unit): DownloadTask
I would like to make it suspending and cancellable, therefore I'd use suspendCancellableCoroutine
to do that, resuming the continuation when onCompleted is invoked.
However, there is a problem with that: if the coroutine is cancelled, the DownloadTask
is cancelled (as intended), but suspendCancellableCoroutine
resumes immediately with a CancellationException
(before the DownloadTask
is actually completed). This is a problem because it is unstructured an the coroutine completes when the background task (the download) is still running.
Here is some code that better explains the problem: https://pl.kotl.in/tm08uP_SB
To solve this I wrote a suspendCancellableCoroutineAwaiting
solution that uses some trick to make sure that the background task is actually awaited before the coroutine is resumed, even when cancelled. However, I'm not particularly satisfied with this solution (conceptually). Is there any better way to achieve this? Thank you!
@OptIn(ExperimentalCoroutinesApi::class)
private suspend inline fun <T> suspendCancellableCoroutineAwaiting(
crossinline block: (CancellableContinuation<T>) -> Unit,
): T {
val job = Job()
return try {
suspendCancellableCoroutine { cont ->
val wrapperContinuation = object : CancellableContinuation<T> by cont {
override fun resumeWith(result: Result<T>) {
job.complete()
cont.resumeWith(result)
}
override fun resume(value: T, onCancellation: ((cause: Throwable) -> Unit)?) {
job.complete()
cont.resume(value, onCancellation)
}
}
block(wrapperContinuation)
}
} finally {
withContext(NonCancellable) {
job.join()
}
}
}
Sam
02/21/2023, 2:39 PMsuspend fun download() = coroutineScope {
val downloadJob = Job()
val task = downloadSomething { downloadJob.complete() }
launch(start = CoroutineStart.ATOMIC) {
try {
awaitCancellation()
} finally {
task.cancel()
}
}
withContext(NonCancellable) {
downloadJob.join()
}
}
DownloadTask
has some sort of cancel
hook. If it doesn’t, it’s effectively not cancellable at all, which makes all of this a bit mootfranztesca
02/22/2023, 3:35 PMawaitCancellation
... right?Sam
02/22/2023, 3:38 PMuli
02/23/2023, 1:26 PMsuspendCoroutine
behave as you need it?franztesca
02/23/2023, 11:24 PMuli
02/24/2023, 8:56 AMSam
02/24/2023, 8:59 AMuli
02/24/2023, 9:06 AMdownloadSomething