The CountDownTimer implementation of Android may not be suitable for all cases as the onTick() method of the CountDownTimer runs on the main/UI thread.
The same could also be achieved using a TimerTask, but we do not have support for Pause/Resume operations when you’re using a Timer and a TimerTask.
The following implementation of a generic Timer runs on a separate thread and hence is most suitable for any operation that does not involve UI updates. It is basically a wrapper around a Runnable scheduled with a ScheduledExecutorService which is part of the java.util.concurrent package. The following is a gist of the core Runnable that handles the tick.
future = execService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { onTick(); elapsedTime += Timer.this.interval; if (duration > 0) { if(elapsedTime >=duration){ onFinish(); future.cancel(false); } } } }, 0, interval, TimeUnit.MILLISECONDS);
For pause, we cancel the Future instance that we obtained when we scheduled the Runnable using the ExecutorService.
future.cancel(false);
For resume, we just schedule the same Runnable again.
We leave the following methods as abstract, to force the classes extending the Timer class to override them.
/** * This method is called periodically with the interval set as the delay between subsequent calls. */ protected abstract void onTick(); /** * This method is called once the timer has run for the specified duration. If the duration was set as infinity, then * this method is never called. */ protected abstract void onFinish();
Following is an example implementation of a concrete class extending the abstract Timer:
public class ExampleTimer extends Timer{ public ExampleTimer() { super(); } public ExampleTimer(long interval, long duration){ super(interval, duration); } @Override protected void onTick() { System.out.println("onTick called!"); } @Override protected void onFinish() { System.out.println("onFinish called!"); } }
Following is a simple test showing the usage of the Timer.
//This creates a timer which will tick every second indefinitely. Timer oneSecondInfiniteTimer = new ExampleTimer(); //This creates a timer which ticks every 2 seconds, and runs for 20 seconds. Timer twoSecondTimer = new ExampleTimer(2000l, 20000l); //Start the timer. twoSecondTimer.start(); //Pause the timer. twoSecondTimer.pause(); //Resume the timer twoSecondTimer.resume();
The whole code is hosted in GitHub (https://github.com/c05mic/pause-resume-timer ) for your copy-pasting pleasure. 🙂
Contributions are welcome!
Hi,
Very good code. I have put textview inside ontick, but its not updating.
protected void onTick() {
System.out.println(“onTick called!”);
long rT = getRemainingTime() / 1000;
System.out.println(String.format(“%02d:%02d:%02d”, rT / 3600, (rT % 3600) / 60, (rT % 60)));
ma.setTv(String.format(“%02d:%02d:%02d”, rT / 3600,(rT % 3600) / 60, (rT % 60)));
}
Regards,
Tariq
Hi, the whole point of writing this timer is to make the onTick run on a background thread. So, if you have to do any UI updates you’ll have to use handler to post to the UI/main thread.
Thanks, but I think you should specify, that there are needs to use `runOnUiThread()` to do something from task. And it will be good, if you post your timer in mvn.
Thanks for the feedback. Good point, I will specify the use of ‘runOnUiThread()’. I can also push this to maven central.