loading...
Cover image for Coroutine Delay

Coroutine Delay

patjackson52 profile image Patrick Jackson Originally published at patrickjackson.dev on ・2 min read
Handler().postDelayed({ doSomething() }, 3000)

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { doSomething() }

A common pattern is to delay execution of some code for a given amount of time. In Android and iOS there are several ways to do, such as the above snippet. How can we pull this into shared Kotlin Multiplatform code?

myCoroutineScope.launch { delay(3000) uiScope.launch { doSomething() } }

Here the uiScope.launch runs the doSomething() function on the main thread. If main thread is not needed uiScope can be left out.

There is one trick here for MPP projects. On iOS this will cause a crash at runtime. On iOS you will need to use a custom Dispatcher. Chances are that you are already as a stopgap until multithreaded coroutine support lands.

Here is a Dispatcher that supports delay() on iOS. Full source can be found in the ReadingList sample app from the ReduxKotlin project:

import kotlinx.coroutines.*
import platform.darwin.*
import kotlin.coroutines.CoroutineContext

\**
 * Dispatches everything on the main thread. This is needed until
 * multithreaded coroutines are supported by kotlin native.
 * Overrides Delay functions to support delay() on native 
 */
@UseExperimental(InternalCoroutinesApi::class) class UI : CoroutineDispatcher(), Delay {
 override fun dispatch(context: CoroutineContext, block: Runnable) {
   val queue = dispatch_get_main_queue()
   dispatch_async(queue) { block.run() }
 }

   @InternalCoroutinesApi
   override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) { 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeMillis  1_000_000), dispatch_get_main_queue()) {
    try {
      with(continuation) {
        resumeUndispatched(Unit)
      }
    } catch (err: Throwable) { 
      logError("UNCAUGHT", err.message ?: "", err)
      throw err
    }
 }
}

 @InternalCoroutinesApi
 override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle {
   val handle = object : DisposableHandle {
     var disposed = false 
       private set
     override fun dispose() {
       disposed = true
       } 
    }
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeMillis 1_000_000), dispatch_get_main_queue()) {
     try { 
        if (!handle.disposed) {
         block.run()
         }
     } catch (err: Throwable) { 
        logError("UNCAUGHT", err.message ?: "", err)
        throw err
      } 
    }
   return handle
 }
}

The post Coroutine Delay appeared first on PatrickJackson.dev.

Posted on by:

patjackson52 profile

Patrick Jackson

@patjackson52

Software Engineer at AbleTo Kotlin, multiple platform Kotlin, Android, iOS

Discussion

markdown guide