Solvedkotlinx.coroutines Replacing Java Timer with Kotlin Coroutine Timer

I often using this method to replace java.util.Timer in my projects:

inline fun startCoroutineTimer(delayMillis: Long = 0, repeatMillis: Long = 0, crossinline action: () -> Unit) = GlobalScope.launch {
    delay(delayMillis)
    if (repeatMillis > 0) {
        while (true) {
            action()
            delay(repeatMillis)
        }
    } else {
        action()
    }
}

java.util.Timer is buggy. On some Android devices, it causes the following crash, even though I re-init the object:

java.lang.IllegalStateException: Timer was canceled

With Kotlin Coroutines, it is possible for me to prevent this terrible error. I hope you add the method I wrote above.

16 Answers

✔️Accepted Answer

You are welcome to use your startCoroutineTimer solution, but we don't plan to a function like startCoroutineTimer to the core library, because it is easy to write, limited to this narrow use-case and cannot be easily composed with other operations.

Our plan is to provide ready-to-use tick-generators (~timers) for Kotlin Flow so that your particular case would be solved with code like this (note, that names are purely tentative here):

tickerFlow(1000)
    .onEach { /* some actions here */ }
    .launchIn(scope)

The advantage of using the flow here is that you can easily use other flow operators to control what happens when the action takes longer than ticker period, etc, without having to provide lots of configuration options to the tickerFlow function itself.

Please, use #540 as an umbrella issue for that work to post your use-cases.

Other Answers:

@JakeWharton I am not sure whether this is related to Coroutine itself since it is an additional method to replace Java Timer. In Java Timer, I write the following code to start a repeated task every 1 second:

val timer = Timer()
timer.schedule(object : TimerTask() {
    override fun run() {
        // some actions
    }
}, 1, 1000) // Minimum delay is 1 millisecond. If lower, it throws IllegalArgumentException

The main backward from Java Timer is, we cannot start the repeated action immediately by setting the delay time to 0ms. Hence, the following approach with Coroutine is possible:

val timer: Job = startCoroutineTimer(delayMillis = 0, repeatMillis = 1000) {
    // some actions
}

Another backward from Java Timer is, it sometimes throws java.lang.IllegalStateException: Timer was canceled and causes app to crash. I tried to re-init the Timer and start a new one. But the error still appears. I don't know why. It affects less than 2% of my users.

I see Crashlytics reported this message. When I migrated to Coroutine timer, the error is gone. I hope you consider adding this method to Coroutine. Thanks in advance.

You probably want this to be a factory for a Flow that emits either Unit or a counter on each tick.

More Issues: