Skip to content

Instantly share code, notes, and snippets.

@elizarov
Created April 24, 2017 08:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elizarov/5a96e695e60c267f1fee934ebd22de5f to your computer and use it in GitHub Desktop.
Save elizarov/5a96e695e60c267f1fee934ebd22de5f to your computer and use it in GitHub Desktop.
Alternative implementation of HandlerContext for Android that continues coroutine with CancellationException when the job is complete (i.e. it was cancelled from outside)
public class CancellableHandlerContext(
private val handler: Handler
) : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor, Delay
{
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
DispatchedContinuation(continuation)
override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) {
handler.postDelayed(object : ResumeTask<Unit>(continuation) {
override fun resume() = continuation.resume(Unit)
}, unit.toMillis(time))
}
override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle {
handler.postDelayed(block, unit.toMillis(time))
return object : DisposableHandle {
override fun dispose() {
handler.removeCallbacks(block)
}
}
}
private abstract inner class ResumeTask<in T>(val continuation: Continuation<T>) : Runnable {
override fun run() {
if (continuation.context[Job]?.isCompleted == true)
continuation.resumeWithException(CancellationException("Cancelled")) else
resume()
}
abstract fun resume()
}
private inner class DispatchedContinuation<T>(val delegate: Continuation<T>) : Continuation<T> {
override val context: CoroutineContext = delegate.context
override fun resume(value: T) {
handler.post(object : ResumeTask<T>(delegate) {
override fun resume() = continuation.resume(value)
})
}
override fun resumeWithException(exception: Throwable) {
handler.post(object : ResumeTask<T>(delegate) {
override fun resume() = continuation.resumeWithException(exception)
})
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment