android-studiokotlinandroid-handler

Kotlin unable to stop handler running


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)
    }
}

Solution

  • 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