I am testing a few things with TimerTask and Timers and android , and i noticed that if i put Looper inside the run () method, the TimerTask runs just once, even though i defined it to be repetitive.Any ideas why is that ?
here is the MainActivity part
Timer timi=new Timer();
timi.scheduleAtFixedRate(new locac(nok,this),10, 1000);
and here is the worker timerTask class
public void run ()
{
Looper.prepare();
int loto=23;
int lato=23;
long time=1220227200;
String test=String.valueOf(lato);
String test3=String.valueOf(loto);
String test1=String.valueOf(time);
dbadapter mkola=new dbadapter(Ctx);
mkola.openToWrite();
mkola.insert(test,test1,test3);
Looper.loop();
}
as soon as i remove the Looper , it works nice.
i need the Looper because at a point i want to invoke some methods inside which initiate a Handler
thanks in advance
It is because your TimrTask never returns (because of the call to Looper.loop() )
Form The Timertask documentation, emphasis mine (Oracle Documentation, Android's is not that clear) http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html
:
Corresponding to each Timer object is a single background thread that
is used to execute all of the timer's tasks, sequentially. Timer tasks
should complete quickly. If a timer task takes excessive time to
complete, it "hogs" the timer's task execution thread. This can, in
turn, delay the execution of subsequent tasks, which may "bunch up"
and execute in rapid succession when (and if) the offending task
finally completes.
So what happens is that your TimerTask is run in the single thread of your Timer and as it's run method never returns it bloks the thread, which cannot run the new scheduled itereation of your TimerTask anymore.
Related
Globally, I have a the following:
Timer timer = new Timer();
in my onResume() I have the following code.
timer.schedule(new syncTimerTask(), 1, 30000);
and my syncTimerTask is as follows :
class syncOutgoingUpdatesTimerTask extends TimerTask
{
public void run()
{
//some sync process with outer back end server
//fetch results etc
myHandler.post(myRunnable);
}
}
my handler and runnable are declared globally as follows
final Handler myHandler = new Handler();
final Runnable myRunnable = new Runnable()
{
public void run()
{
//update GUI, text views whatever.
}
};
And inside my onPause() I call timer.cancel();
The above code is neat, straight to the point and does the job perfectly.
But in order to grasp the idea better, I have some concerns and questions.
Assume the syncing too a lot of time, and the user pressed the back button. This will cause the onPause to get caused , which will stop the timer from repeating itself, however the running TimerTask will continue running. But what happens when the code reaches the line of myHandler.post(myRunnable); where the handler calls the runnable, but there is no GUI to update ? Do I get a null pointer there ?
Assume the sync started and again it took a lot of time, in which state, the user pressed the home button and got out of the app and removed the app from the 'recent apps' which 'kills' the app, calling onDestroy() on all methods. In this case, does the thread of the timer (which is a seperate thread and not the UI thread, stops wherever it is, (even though it might be in the middle) because it is associated with the app ?), assume this is true, the code won't even reach the myHandler.post(myRunnable); so no null pointers will occur.. is this the case ?
Yes, the event will run, and if you nullify things out it might cause problems. The best you can do is to have a flag that tells you, from your Runnable, that the activity is paused.
No, the app is not killed, just stopped (unless the Android process manager kills it for memory as usual). In this case your timer thread continues running and executes the Runnable in the main thread, with the same potential problems of 1.
The articles on the site related to Timer talk about how to use Timer to program.
I ask a different question.
How does Java perform Timer method?
Since it is said to avoid time-consuming work by not to use while loop to check whether the current time is the required time point, I think Timer is not implemented simply by using while loop to continuously checking and comparing the current time to the desired time point.
Thank you!
I think Timer is not implemented simply by using while loop to continuously
checking and comparing the current time to the desired time point.
YES, IT IS. The only optimization is; it is using priority queue based on nextExecutionTime for tasks.
JavaDoc states
Timer object is a single background thread that is used to
execute all of the timer's tasks, sequentially. Timer tasks should
complete quickly. If a timer task takes excessive time to complete,
it "hogs" the timer's task execution thread. This can, in turn, delay
the execution of subsequent tasks
Timer class contains
TaskQueue which is a priority queue of TimerTasks, ordered on nextExecutionTime.
TimerThread(queue) the timer's task execution thread, which waits (queue.wait()) for tasks on the timer queue.
TimerThread has private void mainLoop() { where continuous while(true) will keep checking the tasks by comparing nextExecutionTime with currentTimeMillis
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime<=currentTime)) {
and if it reaches then calling
if (taskFired) // Task fired; run it, holding no locks
task.run();
According for the javadoc
This class does not offer real-time guarantees: it schedules tasks
using the Object.wait(long) method.
If you look in the code you will find a method called main loop. The first couple of lines are copied below.
private void mainLoop() {
while (true) {
try {
And... it uses a while loop inside of it along with Object.wait() to do the waiting.
private ScheduledFuture<?> future;
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable runnable = new Runnable() {
#Override
public void run() {
//my code...
}
};
future = scheduler.scheduleAtFixedRate(runnable, 0, 15,TimeUnit.SECONDS);
I have the aforementioned code in an android activity. So, I press a button and I go to the next activity. If I press the back button or explicitely (from a button) go to the previous activity again, is there any posibility a second timer to be created?
In other words, does the Executors.newScheduledThreadPool(1) verifies me that the runnable will be executed only by one thread and that I will not have for example, two different tasks that both of them will run every 15 seconds?
From documentation http://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor.html
public ScheduledFuture<?> scheduleAtFixedRate (Runnable command, long initialDelay, long period, TimeUnit unit)
Added in API level 1
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on. If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor. If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
So, AFAIU the size of pool 1 and scheduleAtFixedRate ensure that there is only one thread running.
I think that even if you switch Activities, your Runnable will keep running, since the activity context will be saved by the OS.
You should stop your thread when the Activity's onPause or onStop are called, by using:
future.cancel(true);
Then, if you come back to the activity you can schedule the Runnable again.
Sometimes the duration of a repeated task is longer than its period (In my case, this can happen for hours at a time). Think of a repeated task that takes 7 minutes to run and is scheduled to run every 10 minutes, but sometimes takes 15 minutes for each run for a few hours in a row.
The Timer and ScheduledThreadPoolExecutor classes both have a scheduleAtFixedRate method that is usually used for this type of functionality. However, both have the characteristic that they 'try to catch up when they fall behind'. In other words, if a Timer falls behind by a few executions, it builds up a queue of work that will be worked on continuously until it catches back up to the number of runs that would have happened if none of the tasks had taken longer than the specified period. I want to avoid this behavior by skipping the current execution if the previous run is not complete.
I have one solution that involves messing around with the afterExecution method of a pooled executor, recalculating a delay, and rescheduling the runnable with the new delay, but was wondering if there's a simpler way, or if this functionality already exists in a common library somewhere. I know about scheduling with a fixed delay rather than a fixed period, but this will not work for me since it's important to try to execute the tasks at their fixed times. Are there any simpler options than my afterExecution solution?
I think what you want is for the long-running task itself to not run in the ScheduledExecutorService itself, but in a background thread. Then the fixed-rate task will always complete quickly, since it is only used for checking whether to start the actual task in the background (or not, if it's still running from last time).
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
final Runnable actualTask = null;
executorService.scheduleAtFixedRate(new Runnable() {
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private Future<?> lastExecution;
#Override
public void run() {
if (lastExecution != null && !lastExecution.isDone()) {
return;
}
lastExecution = executor.submit(actualTask);
}
}, 10, 10, TimeUnit.MINUTES);
You could use scheduleWithFixedDelay method instead. It's similar but this one does not have a queue for missed runs and instead starts counting again only when the current Runnable was terminated.
The documentation states the reexecution of the Runnable will be scheduled based on the delay parameter:
The delay between the termination of one execution and the commencement of the next.
Make a third class, say called Coordinator. Coordinator has a synchronized startRunning() method which sets isRunning to true and returns true if another thread was not running already. There should also be a synchronized stopRunning method which sets isRunning to false. It returns true if a runnable is already running. You make a single instance of this class and pass a reference to all of the runnables you construct. In the runnable's run method you first call startRunning and check the return to verify that another one isn't running already. Make sure to put the code in run() in a try-finally and call stopRunning from within the finally block.
I tried everything. This one too How to stop the task scheduled in Java.util.Timer class
I have one task that implements java.util.TimerTask
I call that task in 2 ways:
I schedule Timer like this:
timer.schedule(timerTask, 60 * 1000);
sometimes I need that work to start immediately and it has to cancel timerTask if there is any that is working
cancelCurrentWork();
timer.schedule(timerTask, 0);
This implementation doesn't stop current work:
(documentation says: If the task is running when this call occurs, the task will run to completion, but will never run again)
But I need it to stop.
public static void cancelCurrentwork() {
if (timerTask!= null) {
timerTask.cancel();
}
}
This implementation just cancels the timer but leaves currently doing task to be finished.
public static void cancelCurrentwork() {
if (timer!= null) {
timer.cancel();
}
}
Is there a way in timer to STOP current executing taks, something like Thread.kill() or something? When I need that task to stop I want it to loose all its data.
There is no way for the Timer to stop the task in its tracks.
You will need to have a separate mechanism in the running task itself, that checks if it should keep running. You could for instance have an AtomicBoolean keepRunning variable which you set to false when you want the task to terminate.
if your timer is using some sort of file/socket etc, you can close that object from outside the timer, and the timer task will throw an exception, and you can use it to stop the timer.
but in general you need some sort of poison pill to successfully stop a separate thread/timer.