7

I want to display a simple CountDownTimer in a TextView, but it seems to go from 30 down to 28 right away, as if there was a lag in between. I'm not sure how to go about on fixing this small bug. Here is my code:

This is in the click listener of the Button:

new CountDownTimer(30000, 1000) {

    @Override
    public void onTick(long millisUntilFinished) {
        coolDownTimer.setText("Cool Down for: " + String.valueOf(millisUntilFinished / 1000));
    }

    @Override
    public void onFinish() {
        animatedPic.setClickable(true);
        // reregister the proximity sensor
        sm.registerListener(sensorListener, proxSensor, SensorManager.SENSOR_DELAY_NORMAL);
        coolDownTimer.setText("GO!");
    }
}.start();
Xaver Kapeller
  • 49,491
  • 11
  • 98
  • 86
Mo2
  • 1,090
  • 4
  • 13
  • 26
  • Possible duplicate of [Countdown timer starts from a second after it is supposed to](https://stackoverflow.com/questions/35783313/countdown-timer-starts-from-a-second-after-it-is-supposed-to) – deepGrave Feb 24 '19 at 07:27
  • @deepGrave my post is older than the one you've linked. – Mo2 Jun 05 '19 at 22:31

2 Answers2

8

There are 2 issues:

  • The first issue is that the countdown timer doesn't execute until time has elapsed for the first tick, in this case, after 1000ms.

  • The second is that the elapsed time is only approximate. millisUntilFinished is not guaranteed to come in increments of the interval (you can see that if you don't divide by 1000, the first tick is slightly under 29000).

Another thing to keep in mind is that you're not guaranteed to receive a tick call. That is to say, if the device did not have enough time to complete a tick, it may skip it (generally only noticeable for faster intervals).

To solve issue 1, you can simply run the onTick code (or refactor it into its own method) and run it as you start the countdown timer.

For issue 2, you can simply round the number.

For example:

new CountDownTimer(30000, 1000)
   {
        @Override
        public void onTick(long millisUntilFinished)
        {
            performTick(millisUntilFinished);
        }
        @Override
        public void onFinish()
        {
            animatedPic.setClickable(true);
            // reregister the proximity sensor
            sm.registerListener(sensorListener,proxSensor,SensorManager.SENSOR_DELAY_NORMAL);
            coolDownTimer.setText("GO!");
        }
    }.start();

    performTick(30000);


void performTick(long millisUntilFinished) {
    coolDownTimer.setText("Cool Down for: " + String.valueOf(Math.round(millisUntilFinished * 0.001f)));
}


If you want to make sure the appropriate value is updated with minimal latency, you may want to consider reducing the interval.

Allen G
  • 1,160
  • 6
  • 8
  • It seems to run better now, however it skips the last second. It goes from 2 to 0, but with a 2 second interval. – Mo2 Jun 04 '14 at 00:14
  • 1
    Yeah, this is apparently a "feature" of the CountDownTimer. It seems that, prior to executing a tick, the class calculates the remaining time left, and if it's less than the interval, it skips the interval and waits to perform onFinish. For more details, you can refer to this post: http://stackoverflow.com/a/12283400/3704926 A work around suggested there was to change the interval to 500. – Allen G Jun 04 '14 at 00:24
  • Thank you, changing my interval from 1000 to 500 worked. – Mo2 Jun 04 '14 at 00:48
3

It is skipping because CountDownTimer is not a precise timer. Try to print just the millisUntilFinished without dividing it you'll see some excess number that it wont be exactly 29000 when it hits its first tick.

you can refer on this thread for the solution.

Community
  • 1
  • 1
Rod_Algonquin
  • 26,074
  • 6
  • 52
  • 63