androidkotlincoroutinemobile-developmentcontinuations

Working of interceptContinuation() and releaseInterceptedContinuation()


I have read the documentation like ContinuationInterceptor , githhub for the functions interceptContinuation() and releaseInterceptedContinuation(). However, I struggled to understand their usage within coroutines.

I am familiar with the concepts of the internal workings of continuations and coroutine contexts (element and key), dispatchers, and coroutines. Can someone explain these two functions to me in a way that I can fully grasp their operations?


Solution

  • These functions do exactly what the documentation says: they let us intercept all registered continuations and replace or usually wrap them into our own continuation.

    But yes, I know, it is much harder to understand, what it really means and how we could use this. Please see this example:

    suspend fun main() {
        val interceptor = object : ContinuationInterceptor {
            override val key = ContinuationInterceptor
    
            override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> {
                return object : Continuation<T> {
                    override val context = continuation.context
    
                    override fun resumeWith(result: Result<T>) {
                        println("Resuming a continuation")
                        continuation.resumeWith(result)
                    }
                }
            }
        }
    
        withContext(interceptor) {
            println("Going to suspend")
            delay(1000)
            println("Resumed")
        }
    }
    

    We created an interceptor, which wraps all continuations and logs a message before resuming original continuations. Result is something like:

    Going to suspend
    ...
    Resuming a continuation
    Resumed
    

    I'm not entirely sure when exactly interceptContinuation is called. Usually, around the time we suspend, but this is not entirely true. We can assume every continuation which is used by the coroutines machinery, gets intercepted at some point.

    Most notable example of using interceptors are dispatchers. When we suspend, we create a continuation which only "knows" how to get back into the function, recreate its state and start execution. Such continuation resumes directly, it doesn't understand threads, etc. Then the dispatcher intercepts such continuation and wraps it into its own continuation, so the original continuation is e.g. executed in the proper thread pool.

    releaseInterceptedContinuation is similar - it let us do some clean up after the continuation and our wrapper is no longer needed.