I am using a countdown timer for audio notification… and it’s not accurate from the start…
using initial parameters
private final long startCountDown; private final long intervalCountDown; ... startCountDown = 180 * 1000; // 3 mns - to be set from Preferences later intervalCountDown = 60 * 1000; // 1 mns - to be set from Preferences later ... public void onTick(long millisUntilFinished) { Log.d(TAG, "notify countDown: " + millisUntilFinished + " msecs"); } countDownTimer = new SwimCountDownTimer(startCountDown,intervalCountDown); .... public void startCountDown() { Log.d(TAG, "start countDown for " + startCountDown + " msecs" ); countDownTimer.start(); }
I can see in the log that the initial countdown is correctly set to 180000 but the next one should be 120000 and it’s set to 119945 !!!
04-27 14:50:42.146: I/SWIMMER(8670): notify countDown: 180000 msecs 04-27 14:51:42.206: I/SWIMMER(8670): notify countDown: 119945 msecs
This is quite annoying as the audio notifier is expecting to say only ‘2 minutes” and not “1 minute and fifty nine seconds” …; why the interval is not right … ? I can tricj it in setting myself the text to speech string … but is there any way to get correct data ?
thanks for suggestions
Advertisement
Answer
I know it’s an old question- but I’ve also encountered the problem, and thought I would share my solution.
Apperantly CountDownTimer isn’t very accurate, so I’ve decided to implement a more percise countdown timer, using java.util.Timer:
public abstract class PreciseCountdown extends Timer { private long totalTime, interval, delay; private TimerTask task; private long startTime = -1; private boolean restart = false, wasCancelled = false, wasStarted = false; public PreciseCountdown(long totalTime, long interval) { this(totalTime, interval, 0); } public PreciseCountdown(long totalTime, long interval, long delay) { super("PreciseCountdown", true); this.delay = delay; this.interval = interval; this.totalTime = totalTime; this.task = getTask(totalTime); } public void start() { wasStarted = true; this.scheduleAtFixedRate(task, delay, interval); } public void restart() { if(!wasStarted) { start(); } else if(wasCancelled) { wasCancelled = false; this.task = getTask(totalTime); start(); } else{ this.restart = true; } } public void stop() { this.wasCancelled = true; this.task.cancel(); } // Call this when there's no further use for this timer public void dispose(){ cancel(); purge(); } private TimerTask getTask(final long totalTime) { return new TimerTask() { @Override public void run() { long timeLeft; if (startTime < 0 || restart) { startTime = scheduledExecutionTime(); timeLeft = totalTime; restart = false; } else { timeLeft = totalTime - (scheduledExecutionTime() - startTime); if (timeLeft <= 0) { this.cancel(); startTime = -1; onFinished(); return; } } onTick(timeLeft); } }; } public abstract void onTick(long timeLeft); public abstract void onFinished(); }
Usage example would be:
this.countDown = new PreciseCountdown(totalTime, interval, delay) { @Override public void onTick(long timeLeft) { // update.. // note that this runs on a different thread, so to update any GUI components you need to use Activity.runOnUiThread() } @Override public void onFinished() { onTick(0); // when the timer finishes onTick isn't called // count down is finished } };
to start the countdown, simply call countDown.start(). countDown.stop() stops the countDown, which could be restarted using countDown.restart().
Hope this is any help for anyone in the future.