1

I'm trying to create a countdown timer optimised for tablets, and it runs fine except for the slight detail that it gradually loses time, over time: over 5 mins it loses probably 1-2 seconds, when testing on my Xoom.

Here is my onTick code:

        public void onTick(long millisUntilFinished) {
        // TODO Auto-generated method stub
        currentTime = System.currentTimeMillis();
        currentCount = startTime - currentTime;
        //currentCount = millisUntilFinished;
        displayCorrectTime();
    }

Initially I started with just using the 'millisUntilFinished', when I noticed the time was slipping. I then read around and tried to get it to sync up better by using the difference between the start time and 'now' to inform the timer. Unfortunately, both methods seem to lose time (I don't really understand how this second method can lose time, but nevertheless).

Any suggestions?

Diesel
  • 11
  • 2
  • This might be useful: http://stackoverflow.com/questions/5839152/why-do-system-nanotime-and-system-currenttimemillis-drift-apart-so-rapidly – David Given Mar 04 '12 at 10:33

3 Answers3

0
new CountDownTimer(60000, 1000) { 
        long startTime = System.currentTimeMillis();
        public void onTick(long millisUntilFinished) {
            long timePassed = System.currentTimeMillis() - startTime;
            pb.setProgress(60000-(int)timePassed);
            t.setText(String.valueOf((60000-timePassed)/1000));
        }

        public void onFinish() {
            Intent intent = new Intent(GameActivity.this, SummaryActivity.class);
            startActivity(intent);
        }
    }.start();

This worked for me. It's a count down timer of 1 minute with a progressbar display.

Aïssa
  • 670
  • 8
  • 10
0

Here's a simple function I wrote a very long time ago for Java server apps:

/// <summary>
/// A static helper class the enables a thread to sleep for a specific period of
/// time, manage drift and supports clock changes.
/// </summary>
public static class ThreadHelper
{
    /// <summary>
    /// Enables a thread to sleep for a specific period of time, manage drift and
    /// supports clock changes. This function enables the user to break from the
    /// call.
    /// </summary>
    /// <param name="startTicks">A long value that specifies the time to start sleeping.</param>
    /// <param name="intervalTicks">The long value that specifies the duration to sleep for.</param>
    /// <param name="signalStop">A reference to a bool that enables the caller to
    /// break out of this call from another thread.</param>
    /// <returns>A long value that specifies the value the caller should use for the
    /// startTicks parameters on subsequent calls into this function.</returns>
    public static long Sleep(long startTicks, long intervalTicks, ref bool signalStop)
    {
        long finalTicks = startTicks + intervalTicks;

        while (finalTicks + intervalTicks < DateTime.Now.Ticks)
        {
            finalTicks += intervalTicks;
        }

        while (!signalStop && DateTime.Now.Ticks < finalTicks)
        {
            while (finalTicks - intervalTicks > DateTime.Now.Ticks)
            {
                finalTicks -= intervalTicks;
            }

            Thread.Sleep(1000);
        }
        return finalTicks;
    }
}
Mike
  • 559
  • 5
  • 21
0

That's normal, the System.currentTimeMillis() has that inprecision. You can try System.nanoTime() for a (theoretical) better precision. At any rate, you need to compensate for the time it takes to execute the displayCorrectTime() call.

Better solution would be to use :

http://developer.android.com/reference/java/util/Timer.html

Shivan Dragon
  • 15,004
  • 9
  • 62
  • 103
  • hmm .. haven't come across timer yet (I'm a noob) .. got some reading to do. Also, what do you mean by 'compensate'? – Diesel Mar 04 '12 at 09:49
  • You want the method displayCorrectTime() to be exectued every (let's say) 300 ms. That method call will take a slightly different time each time you call it (like sometimes it might be 10 ms, sometimes 23 ms). So to always call it after 300 ms from the last call, you should measure how much time passed between calls (like you do now ) AND how much time the last method call took. When the time past MINUS the call time depass 300ms it's time to call the method again. Look up some basics on how to create a game loop: http://p-xr.com/android-tutorial-how-to-make-a-basic-game-loop-and-fps-counter/ – Shivan Dragon Mar 05 '12 at 08:59