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?
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 .
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.
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).
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".
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With