4

I have a scenario where I need to run a certain task at specific interval, however, I want to be able to reset/restart the timer without reinstantiating. Here's my code for better understanding.

private TimerTask beatTask = new TimerTask() {
        @Override
        public void run() {
            beatDetected();
        }
    };

public void beatDetected() {
        timeoutTimer.cancel();

        // handle my stuff and restart the timer.

        timeoutTimer.schedule(beatTask, 2000);
    }

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

        (timeoutTimer = new Timer()).schedule(beatTask, 2000);

        return Service.START_STICKY;
    }

The idea behind this implementation is that beatDetected() can be called from outside event, in which case the next timer tick should happen from that moment on i.e. the elapsed time for the next task should be reset. However, I only get the first tick, and from that point on, the timer just doesn't work. I'm not limited to using Timer class, anything that will solve the above scenario will work. I was thinging about using postDelayed, but this code is located in a Service, and I don't really need UI thread aware updates.

Tomislav Markovski
  • 12,331
  • 7
  • 50
  • 72

2 Answers2

12

Using separate thread for timer is considered a somewhat bad practice on Android devices. That's because you are going to waste resources in most scenarios.

If you don't need super precise timing events, you should go with Handler based timers. An example of such timer can be seen here: Repeat a task with a time delay?. This approach works both for Activities and Services.

Also keep in mind that both Handler and Timer based timers will be paused if device goes to sleep mode. If this is not what you need, then use AlarmManager (but keep in mind that using AlarmManager incorrectly may lead to very bad battery performance).


Reseting the Handler based timer:

 void resetRepeatingTask() {
     mHandler.removeCallbacks(mBeatDetector);
     mHandler.postDelayed(mBeatDetector, mInterval);         
 }
Community
  • 1
  • 1
inazaruk
  • 74,247
  • 24
  • 188
  • 156
  • I have looked into Handler and AlarmManager. Considering my task is repeating every 2 sec, AlarmManager is not the best option. In essence Handler and Timer will do the same thing. However, my problem is being able to reset the "next tick" while the timer/handler is running. – Tomislav Markovski Dec 06 '11 at 18:27
  • Yeap, AlarmManager is too "heavy" for this. To reset `Handler` just call `Handler.removeCallbacks()` and than `Handler.postDelayed()` again. This will restart the delay. – inazaruk Dec 06 '11 at 18:30
  • Updated answer with "reset timer" example. – inazaruk Dec 06 '11 at 18:34
  • Note that: `mBeatDetector` == `mStatusChecker`. – ankalagba Dec 28 '20 at 18:18
5

The accepted answer does not work (at least not for me).

A simple solution uses a Timer to trigger a TimerTask, which can easily be reset.

Log.d(TAG, "Restarting timer");
if (timer != null) {
    timer.cancel();
}
timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        Log.d(TAG, "Run the task");
    }
}, 1000);

Note that a new TimerTask must be created every time you reset the timer - you can't reuse the old one. If you want to preserve state you will need to get the timer task to run a separate task.

IanS
  • 1,459
  • 1
  • 18
  • 23