Changing Android system clock stops timers. How can I restart them?
Asked Answered
K

1

9

I need to run a periodic task in an Android application. I currently use a timer like this:

final Handler guiHandler = new Handler();

// the task to run
final Runnable myRunnable = new Runnable() {

    @Override
    public void run() {
        doMyStuff();
    }
};

Timer timer = new Timer();
timer.schedule(new TimerTask() {

    @Override
    public void run() {
        guiHandler.post(myRunnable);
    }
}, 0, 30000); // run every 30 seconds

This does exactly what I need, but there is a problem: if I change the time on the emulator or phone, the timer stops running. This is what appears in the log when I change the time:

D/SystemClock(  331): Setting time of day to sec=1278920137
W/SystemClock(  331): Unable to set rtc to 1278920137: Invalid argument

Nothing about the timer being interrupted, but it clearly doesn't run anymore after the system clock has changed. I need the task to keep running all the time as long as the application is running.

How can I restart the timer if it gets stopped like this? There's no method on the Timer or TimerTask to check whether it's currently running, so I can't know when to reschedule it. Any ideas?

Kalgoorlie answered 12/7, 2010 at 8:54 Comment(1)
Is this a bug in Android? Seems totally lame that a system-clock set should stop and disrupt applications.Githens
U
4

I think there are a few ways to do this. I wouldn't use the timer in either case.

You can use a handler to run your task in a postDelayed call. Your task would then have to re-register itself with the handler from within itself.

final int ONE_SECOND = 1000; // one second
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
   public void run() {
      ... // do some stuff
      if (expression) {
         handler.postDelayed(this, ONE_SECOND);
      }
   }
}, ONE_SECOND);

This will keep the task running while your app is alive. You can also adjust the delayed rate in the postDelayed within the Runnable. This way is semi predictable as long as you make another Looper. Using the main thread may or may not be appropriate depending on what the task is.

There is also an AlarmManager, that you can gain access to via the Context interface, which is meant for recurring tasks tasks at more precise intervals. It's a little more complex to use but you get the flexibility of having use of the RTC and persisted repeatable tasks.

AlarmManager manager = mContext.getSystemService(Context.ALARM_SERVICE);
manager.setRepeating(AlarmManager.RTC, 
    <start_time_millis>, 
    <period_millis>, 
    pendingIntent);

For example, the pending intent can fire a broadcast intent that you can listen to elsewhere. You can create this pendingintent in the onCreate of your custom Application object and cancel the intent in the onTerminate().

Unaesthetic answered 17/8, 2010 at 5:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.