Kotlin: call a function every second

Problem: Timer class uses a background thread with a queue to queue and execute all tasks sequentially. From your code, because you update UI (changing TextView content in minusOneSecond function). That why the app throws the following exception and make your app crash.

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Solution: There are many ways to achieve your task, but I prefer using post() and postDelayed() method from Handler class. Because it's simple and easy to understand.

val mainHandler = Handler(Looper.getMainLooper())

mainHandler.post(object : Runnable {
    override fun run() {
        minusOneSecond()
        mainHandler.postDelayed(this, 1000)
    }
})

Update: From author's comment about how to pause/resume the task from Handler. Here is an example.

class MainActivityKt : AppCompatActivity() {

    lateinit var mainHandler: Handler

    private val updateTextTask = object : Runnable {
        override fun run() {
            minusOneSecond()
            mainHandler.postDelayed(this, 1000)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Your logic code
        ...
        mainHandler = Handler(Looper.getMainLooper())
    }

    override fun onPause() {
        super.onPause()
        mainHandler.removeCallbacks(updateTextTask)
    }

    override fun onResume() {
        super.onResume()
        mainHandler.post(updateTextTask)
    }

    fun minusOneSecond() {
        if secondsLeft > 0 {
            secondsLeft -= 1
            seconds_thegame.text = secondsLeft.toString()
        }
    }
}

I am using this code to update a clock every minute

 fixedRateTimer("timer", false, 0L, 60 * 1000) {
     [email protected] {
         tvTime.text = SimpleDateFormat("dd MMM - HH:mm", Locale.US).format(Date())
     }
 }

so you have to run it with paratemer 1000 instead of 60*1000

Tags:

Android

Kotlin