Szomti
Szomti

Reputation: 57

How to create timer in Android Studio ( kotlin )?

i wanted to create a program in Android Studio, using kotlin, where i use timer which does an action every ~20 milliseconds and runs infinitely. I used something like this:

object : CountDownTimer(10000,20){
   override fun onTick(millisUntilFinished: Long) {

   }
   override fun onFinish() {
      start()
   }
}.start()

But the problem is, after some time, the timer starts slowing down, and when 1 sec should pass, it actually is 6 seconds. Changing the actions to 40 milliseconds or more only helps for a little while, because later it still slows down. I saw that people used timer that actually works like this without any problem, but it was in Java, and when i tried to change it into Kotlin with Android Studio's help (i never used Java), it ended up not working (after launching, the app crashed everytime). Does someone know how to create or use different timer other than CountDownTimer that i showed above which is in kotlin?

Edit: I forgot to add the code that works for me. It's basically the one i accepted as answer but i had to make some changes to make it work, so here it is:

val timerName = lifecycleScope.launch(Dispatchers.IO) {
   while (isActive) {
      lifecycleScope.launch {
        doSomething()
      }
   delay(20L)
   }
}

Upvotes: 0

Views: 3956

Answers (1)

buszi
buszi

Reputation: 146

It most probably happens because the function in onTick() and onFinish() are invoked within the same coroutine that the counter works, so probably you would need to launch another coroutine there to not block the timer scope

Also this CountDownTimer API is experimental at this moment so I guess it is not really recomended to use it, probably you could do something like this:

val timerJob = scope.launch(Dispatcher.IO) {
   while (isActive) {
       scope.launch { doSomething() }
       delay(20L)
   }
}

I didn't test it but it should have exactly same behavior (but not blocking the timer), it will run until the scope will cancel itself (f.e. lifecycle scopes) or you will cancel it manually by calling timerJob.cancel()

The isActive boolean takes care of checking if coroutine is still active (so the loop won't "leak")

Unfortunately if you run some heavy stuff in this doSomething() call that will exceed this 20 milisec delay there will happen some concurrency issues so it should be simple

If your "game" is so heavy that this 20 milisec delay will be too small then most probably using coroutines is not the best approach for your idea

Upvotes: 1

Related Questions