Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a timer using Handler in Kotlin

Tags:

android

kotlin

I'm trying to implement an Android timer in Kotlin which will fire an event at a defined time interval. I dont want to use TimerTask due to its documented weaknesses (see here) and although there are potentially other ways to do it, I'd like to use a Handler/Runnable in a post-delayed loop. In Java this is possible since the Runnable can refer to itself in the initializer, however in Kotlin it seems this is not possible:

private fun startBoutiqueRefreshTimer(delayMs: Long) {
    val handler = Handler()
    val runnable = Runnable() {
        EventManager.post(BoutiqueRefreshTimerEvent())
        handler.postDelayed(runnable, delayMs)
    }
    handler.postDelayed(runnable, delayMs)
}

because runnable cannot be resolved in the inner postDelayed call. Kotlin apparently prevents variable references from within their own initializers.

What would be a good solution to this problem, still using the Handler/Runnable approach?

like image 410
Michael Scott Avatar asked Sep 01 '17 13:09

Michael Scott


People also ask

How do you make kotlin handler?

1. Run handler in main thread. Looper includes a helper function, getMainLooper() , which retrieves the Looper of the main thread. You can run code in the main thread by using this Looper to create a Handler .

How do I add time to a countdown Timer Kotlin?

You can't change the remaining time on an already-created CountDownTimer. Looking at the source, both millisInFuture and countDownInterval are assigned to final variables; you can't change them. Now, the mStopTimeInFuture variable, the one the timer actually uses to stop, isn't final, and can be changed.

What is the difference between Android Timer and a handler to do action every n seconds?

Handler is better than TimerTask . The Java TimerTask and the Android Handler both allow you to schedule delayed and repeated tasks on background threads. However, the literature overwhelmingly recommends using Handler over TimerTask in Android (see here, here, here, here, here, and here).


3 Answers

This will work

val updateHandler = Handler()

    val runnable = Runnable {
        updateDisplay() // some action(s)
    }

    updateHandler.postDelayed(runnable, 5000).

private fun updateDisplay() {
      Do actions
}

Or if you are not too much familiar with Kotlin, write your code and convert your android Code to Kotlin using Ctrl+Alt+Shift+K".

like image 79
Daya Shankar Avatar answered Oct 16 '22 17:10

Daya Shankar


You could also use something like this:

private fun startBoutiqueRefreshTimer(delayMs: Long) {
    Handler().apply {
        val runnable = object : Runnable {
            override fun run() {
                EventManager.post(BoutiqueRefreshTimerEvent())
                postDelayed(this, delayMs)
            }
        }
        postDelayed(runnable, delayMs)
    }
}

I used here apply() function to simplify Handler variable, and object expression to allow referencing to Runnable.

As you can see, when I used object expression to initialize Runnable (instead of lambda), then I can use this to reference to Runnable object.

like image 9
Kamil Kamiński Avatar answered Oct 16 '22 18:10

Kamil Kamiński


You could move the routine you want to execute periodically in a separate function:

val runnable = Runnable { doJob() }

fun doJob() {
    EventManager.post(BoutiqueRefreshTimerEvent())
    handler.postDelayed(runnable, delayMs)
}

Note that the variable runnable needs to be accessable in scope of the doJob()-function, that means it should be a class-member, if you are in a class/object.

like image 5
Piwo Avatar answered Oct 16 '22 19:10

Piwo