Search code examples
javaandroidtimercountdown

In Java (android), what is a good way to create accurate consecutive timers?


What would be the most accurate solution to have multiple consecutive timers in Java / android? Or in other words, what is the best option to delay the next piece of code until the current timer has finished?

Background information if the question is unclear: To practice coding, I would like to create a free app w/o ads to help practice freediving. The basic idea is to have several timers that run after each other. Example:

  1. 2 minutes breath up
  2. hold your breath for 2 minutes
  3. 2 minutes breath up
  4. hold your breath for 2 minutes + 15 seconds
  5. 2 minutes breath up
  6. hold your breath for 2 minutes + 15 seconds + 15 seconds and so on; usually 8 rounds of breath holding which leads to 16 consecutive timers

At first I thought I can use the timer class but I don't know how to pause the code until the timer is finished. So all the timers ran simultaneously. I have read about CountDownLatch and Handler but I don't have enough experience to judge what would be best for my purpose. I did a python version before and used sleep. It worked fine, but for longer timers it was inaccurate by a few seconds which is a problem.

Another option, I believe, is to use a regular timer but run a while loop until the displayed text == 0. I don't know if this infinite loop would crash the application, interfere with the timer's accuracy or has any other negative side effects.

Any help / thoughts would be appreciated. Thanks!


Solution

  • I suggest you to check System time every few milliseconds.
    You can achieve the same effect via System.currentTimeMillis() and Handler.

    1. save the System time at the beginning of timer.
    2. Set Handler to run every 100 ms(0.1 second) and check the current System time.
    3. If (current time - beginning time) > 2000, proceed next step.

    Something like below...

    class TimerHandler extends Handler
    {
        private long start;
        private long timeGap;
    
        public void set(long gap)
        {
            start = System.currentTimeMillis();
            this.timeGap = gap;
        }
    
        @Override
        public void handleMessage(Message msg)
        {
            long curr = System.currentTimeMillis();
            if(curr - start > timeGap)
            {
                // do what you want.
                // If you want your timer to keep on running,
                // reset start.
            }
    
            // send Next Message after 100 ms.
            sendEmptyMessageDelayed(-1, 100);
        }
    }
    

    In your Activity or something:

    public void startTimer(long gap)
    {
        TimerHandler handler = new TimerHandler();
        handler.set(gap);
        handler.sendEmptyMessageDelayed(-1, 100);
    }
    
    startTimer(2000);
    


    Note that you can reduce error by using small nextTimer when calling sendEmptyMessageDelayed(), but it will cause your OS to check your Thread more frequently, which is not a good idea.