0

My intention is to create an timer which starts from 00:00:00 and hangs together with a recording function. This recording is done in a service so, the timer is also in the same service. If the app moves to the background, the recording and thus the timer keep on going and the app picks the time up at the onResume with a myService.getTime().

But I experience two strange things. The first is that my timer sometimes goed faster than a second, sometimes slower, sometimes jumps from for example 00:00:04 to 00:00:06 etc. There is no consitency in it. I use the code below, but there might be a better option to solve this? The second is that it is causing a lag on my button, although I am starting it in a service?

SERVICE

//////////TIMER FUNCTION START//////////

        private void startTimerClick() {

            if (stopped) {
                startTime = System.currentTimeMillis() - elapsedTime;
            } else {
                startTime = System.currentTimeMillis();
            }
            mHandler.removeCallbacks(startTimer);
            mHandler.postDelayed(startTimer, 0);

        }

        private void pauseTimerClick() {
            mHandler.removeCallbacks(startTimer);
            stopped = true;

        }

        private void stopTimerClick() {
            mHandler.removeCallbacks(startTimer);
            stopped = false;

        }

        private void startTimer() {

            startTimer = new Runnable() {
                public void run() {
                    elapsedTime = System.currentTimeMillis() - startTime;
                    updateTimer(elapsedTime);
                    mHandler.postDelayed(this, REFRESH_RATE);
                }
            };

        }

        private void updateTimer(float time) {
            secs = (long) (time / 1000);
            mins = (long) ((time / 1000) / 60);
            hrs = (long) (((time / 1000) / 60) / 60);

            /*
             * Convert the seconds to String and format to ensure it has a leading
             * zero when required
             */
            secs = secs % 60;
            seconds = String.valueOf(secs);
            if (secs == 0) {
                seconds = "00";
            }
            if (secs < 10 && secs > 0) {
                seconds = "0" + seconds;
            }

            /* Convert the minutes to String and format the String */

            mins = mins % 60;
            minutes = String.valueOf(mins);
            if (mins == 0) {
                minutes = "00";
            }
            if (mins < 10 && mins > 0) {
                minutes = "0" + minutes;
            }

            /* Convert the hours to String and format the String */

            hours = String.valueOf(hrs);
            if (hrs == 0) {
                hours = "00";
            }
            if (hrs < 10 && hrs > 0) {
                hours = "0" + hours;
            }


        }
        //////////TIMER FUNCTION END////////////


    public String getHours(){

        return hours;
    }

    public String getMinutes(){

        return minutes;
    }

    public String getSeconds(){

        return seconds;
    }
}

ACTIVITY(/FRAGMENT)

private void timerStart() {

        handler = new Handler();
        Thread t = new Thread() {

              @Override
              public void run() {
                try {
                  while (!isInterrupted()) {
                    Thread.sleep(1000);
                    handler.post(new Runnable() {
                      @Override
                      public void run() {

                          timer.setText(myService.getHours()+":"+myService.getMinutes()+":"+myService.getSeconds());
                      }
                    });
                  }
                } catch (InterruptedException e) {
                }
              }
            };

            t.start();

    }
Matthias Vanb
  • 923
  • 5
  • 14
  • 32

1 Answers1

0

You are using Threads both in your Service and in your Activity/Fragment code. Using threads for time sensitive tasks in Android is a problem because Android is able to significantly delay threads.

I have been using a ScheduledThreadPoolExecutor for a similar task and it worked great.

You are then using it like this:

ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); // where 1 is the number of needed concurrent threads. 1 should last for your needs.
executor.scheduleWithFixedDelay(new TimerTask() {  
    // your recurringly executed code here
}, 0, 1, TimeUnit.SECONDS);
Undo
  • 25,519
  • 37
  • 106
  • 129
hoelle2011
  • 23
  • 5
  • Would it also be a solution to save the starttime in the service, and to do the timing itself just in the main activity/fragment? @hoelle2011 – Matthias Vanb Apr 03 '13 at 23:28
  • I guess you use the service to keep your app alive when in background operation. It is of course possible to hold the starttime in a service member but maybe another place would be more appropriate then. If you need the timer for any other background task then you should probably keep it in the service. Think of tasks like creating a notification after a certain amount of time - even when the ui is not visible and thus the timer in the activity/fragment may not execute. – hoelle2011 May 16 '13 at 08:15