How to implement timer with Kotlin coroutines

Roman Nazarevych picture Roman Nazarevych · Feb 22, 2019 · Viewed 16.8k times · Source

I want to implement timer using Kotlin coroutines, something similar to this implemented with RxJava:

       Flowable.interval(0, 5, TimeUnit.SECONDS)
                    .observeOn(AndroidSchedulers.mainThread())
                    .map { LocalDateTime.now() }
                    .distinctUntilChanged { old, new ->
                        old.minute == new.minute
                    }
                    .subscribe {
                        setDateTime(it)
                    }

It will emit LocalDateTime every new minute.

Answer

Joffrey picture Joffrey · Feb 22, 2019

I believe it is still experimental, but you may use a TickerChannel to produce values every X millis:

val tickerChannel = ticker(delayMillis = 60_000, initialDelayMillis = 0)

repeat(10) {
    tickerChannel.receive()
    val currentTime = LocalDateTime.now()
    println(currentTime)
}

If you need to carry on doing your work while your "subscribe" does something for each "tick", you may launch a background coroutine that will read from this channel and do the thing you want:

val tickerChannel = ticker(delayMillis = 60_000, initialDelayMillis = 0)

launch {
    for (event in tickerChannel) {
        // the 'event' variable is of type Unit, so we don't really care about it
        val currentTime = LocalDateTime.now()
        println(currentTime)
    }
}

delay(1000)

// when you're done with the ticker and don't want more events
tickerChannel.cancel()

If you want to stop from inside the loop, you can simply break out of it, and then cancel the channel:

val ticker = ticker(500, 0)

var count = 0

for (event in ticker) {
    count++
    if (count == 4) {
        break
    } else {
        println(count)
    }
}

ticker.cancel()