I am running a handler that updates a textView element. The handler is started and stopped at the click of a button but once I start it, I cannot stop it.
fun updateTextView(handler: Handler, run: Boolean = true) {
val runnable: Runnable = object : Runnable {
override fun run() {
// update text view element
handler.postDelayed(this, 500)
}
}
if (run) handler.postDelayed(runnable, 500)
// this should stop it?
else handler.removeCallbacks(runnable)
}
And my function to detect clicks
val textHandler = Handler(Looper.getMainLooper())
private fun setupClickListeners() {
startLive.setOnClickListener{
updateTextView(textHandler)
}
stopLive.setOnClickListener{
updateTextView(textHandler, run = false)
}
}
This is a general way to do what you need:
// store an instance of your runnable task
val runnable: Runnable = object : Runnable {
override fun run() {
// update text view element
handler.postDelayed(this, 500)
}
}
fun startRunnable() {
// you could just run it to get it going, since it posts itself
runnable.run()
}
fun stopRunnable() {
// remove this specific instance from the message queue
handler.removeCallbacks(runnable)
}
Like I said in the comment, your version is creating a new Runnable
instance every time you run the function - then after posting it to the queue, it immediately removes it again. If you didn't remove it, it would run - but you wouldn't be able to stop it, because you don't have a stored reference to the instance you created, so you can't pass it to removeCallbacks
. (Running the function again like you're doing just creates a new Runnable
, so cancelling that won't affect the other one.)
By storing the Runnable
as a variable, you have access to it - so you can easily pass it to removeCallbacks
, and reuse it by posting it again. This doesn't work if you actually need multiple instances (like you have separate tasks going on) - in that case, you'd need to store references to each Runnable
you create, and have some way to coordinate which one you're cancelling