So I looked at so many sources and whenever there is such a problem, it's because the countdowntimer is trying to get cancelled from inside the ontick. This is not my issue. I have the countdowntimer in a runnable. I cancel the timer, I cancel the runnable and it still somehow gets called. Here is some code below. I appreciate any help!
Handler myHandler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
CountDownTimer countdownTimer = new CountDownTimer(difference - (1000 * 60) + 2000, 60000) {
public void onTick(long millisUntilFinished) { // some work here
}
public void onFinish() {
// some other work here
};
data.get(i).setCountDownTimer(countdownTimer);
data.get(i).getCountDownTimer().start();
}
};
data.get(i).setHandler(myHandler);
data.get(i).setRunnable(runnable);
data.get(i).start(2000);
The start function is basically:
public void start(int milliseconds){
handler.postDelayed(runnable, milliseconds);
}
data is just a list of objects where each has its own runnable, handler and countdowntimer.
Here is what I do when I cancel:
data.get(i).getCountDownTimer().cancel();
data.get(i).terminate();
The terminate function is basically:
public void terminate() {
handler.removeCallbacks(runnable);
}
Someone please tell me why the countdowntimer somehow still runs after I cancel it the way I do above; thanks!
UPDATE
In onFinish, I have another countdown that is on a smaller interval. Is onFinish called when I cancel a CountDownTimer? Otherwise I'm really out of ideas! Thanks.
Although you made a good effort to post the relevant pieces of your code, I'm having a hard time imagining how they all fit together. For example, when you create the Runnable for each data object, are the calls to set and start the countdown timer really in the run() method as shown? I'm wondering how data and i are accessible at that point. And if they are truly accessible, how you know that i will have the desired value when the Runnable comes out of the queue and executes?
I agree that cancel() should cause the CountDownTimer to stop. Note however that if start() is called after cancel() the timer will start anew--it's not a one-shot. If a bug is causing start() to be called a second time, it will look like the cancel didn't work.
All I can suggest is that you add a bunch of Log statements throughout your code to confirm your assumptions about when timers are starting and being cancelled, and what the value of i is for each instance.
This was a very silly mistake on my end. When I was removing an object from the data list, I was cancelling the alarm via:
data.get(i).getCountDownTimer().cancel();
And then I remove the object, and notifyitemremoved. The mistake is that I should notifyitemchanged, and in the onbind, I should cancel it. Then I should remove the entry safely knowing the CTD has been cancelled. Anyway, thanks everyone for the input.
Related
In essence, I have an onGuildMessageReceived method that listens for a command alarm with which a user can set a countdown to notify him with a message. They type a time amount and eventual alarm message that comes with the ping they will get after that time.
My question is, how can I make this feature work for each user separately, so other users don't overwrite previous alarm times that were already ticking?
This method is called in the main code to start the countdown.
public void StartTimer(int seconds, GuildMessageReceivedEvent event)
{
timer = new Timer();
timer.schedule(new TimerReminder(event), seconds * 1000);
}
public void StartTimer(int seconds, GuildMessageReceivedEvent event, String text)
{
timer = new Timer();
timer.schedule(new TimerReminder(event, text), seconds * 1000);
}
I have this subclass that does a block of code after the .schedule() time.
class TimerReminder extends TimerTask{
GuildMessageReceivedEvent eventtrigger;
String alarmText = "";
private TimerReminder(GuildMessageReceivedEvent event)
{
eventtrigger=event;
}
private TimerReminder(GuildMessageReceivedEvent event, String alarmArg)
{
eventtrigger=event;
alarmText=alarmArg;
}
public void run()
{
if(alarmText.isEmpty())
{
eventtrigger.getChannel().sendMessage("<#"+auth+">, ***your alarm is ringing!***ππππ").queue();
timer.cancel(); // Terminate the timer thread
}
else
{
eventtrigger.getChannel().sendMessage("<#"+auth+">:\n"+alarmText).queue();
timer.cancel(); // Terminate the timer thread
alarmText="";
}
}
}
At the end of each task, you're running cancel on the timer reference which cancels not the timer that is currently running (Unless no one else ran the command) but rather the timer object that is assigned at the moment to the timer reference which makes it seem like the timers are overwriting each other.
And even if you kept a reference to all of the timers so you could cancel them, there's no need for you to cancel the timer after the task completes, the timer terminates itself.
Furthermore, there's no need for you to keep a static reference to the timer that is currently running, or keep a reference to them at all. When you create a timer a background thread keeps a reference to the timer and the task so they won't get garbage collected. You'd be better off creating the timer as a local variable when the command is run, scheduling the timer and that's it.
If you want the ability to cancel the timers by a different command or whatever you have in mind, then you should keep a list or map with references to all the current timers so you can cancel them if needed.
How do I run a specific set of instructions inside the TimerTask continuously without delay for a set amount of time ? Below are the codes I am attempting to implement the above.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
System.out.println("Test started at: " + new Date());
// Do something continuously without delay
System.out.println("Test finished at: " + new Date());
}
}, 0);
The second parameter to the schedule method is the time to begin the timer task (or delay relative to now), not the length of time that the timer will execute for.
It's not completely clear from your question but I'm assuming you want the task to start and stop at particular times (or delays relative to now) in the future. If so, the way I would approach this is to create a Thread that does the task you need. Since a TimerTask is a Runnable that is executed as a Thread once the Timer starts it, you can just use an instance of that TimerTask. Ensure that Runnable contains a settable field like running. In that Thread, run your task in a while loop like this:
public void run() {
while(running) { /* do my task */ }
}
Then, use one Timer to schedule the Runnable to start at the time you need. Use another Timer to set the running parameter of the same Thread to false at the time you want it to stop. The running parameter should be volatile to ensure that changes to it from the second timer Thread are seen by the first timer Thread immediately. So it would look something like this (not tested):
class StoppableTimerTask extends TimerTask {
private volatile boolean running = true;
public void stopRunning() { this.running = false; }
public void run() {
while(running) { /* do my task */ }
}
}
final StoppableTimerTask task = new StoppableTimerTask();
timer.schedule(task, startTime);
timer.schedule(new TimerTask() {
public void run() {
task.stopRunning();
}
}, stopTime);
Depending on what your "something" is, you may also want to look into Thread interrupts. For example, if it is doing blocking IO, your code won't loop and check the running value until the blocking IO completes. Interrupting the thread (may) cause that to happen. See http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#interrupt--. This may or may not work, and it can be tricky to get right, so if you need this Thread to exit as close to the desired time as possible, prefer running blocking I/O and similar operations with smaller timeouts so that the thread can check whether it should continue to run more often.
UPDATE: As per the comment indicating that the task should start right away, it becomes even simpler. The initial task doesn't even need to extend TimerTask -- it can just be a regular Thread that is started immediately. The timer is only needed to stop it at the specified future time.
i have a problem with a method that i want to be called every x seconds.
In the constructor of my class I have something like that :
public class MyClass extends RelativeLayout{
public MyClass(Context context) {
// bla blaβ¦.
mTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
callMyMethodPeriodically();
}
}, 0, 20000); // every 20 seconds..
}
}
When I press the back button, the callMyMethodPeriodically method still is being called..
Even if i exit the application!
Do you have any ideas?? How can i stop this periodically calling?
Thank you
Try to override the onPause method on your Activity, the onPause will be called when the system is about to start resuming a previous activity. This is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, etc. Implementations of this method must be very quick because the next activity will not be resumed until this method returns.
#Override
protected void onPause() {
super.onPause();
mTimer.cancel();
mTimer.purge();
mTimer = null;
}
You can try timer.canel() method or you can do it by this way
private Runnable runnable = new Runnable()
{
public void run()
{
//
// Do the stuff
//
handler.postDelayed(this, 1000);
}
};
and to stop:
handler.removeCallbacks(runnable);
or this way
you could look into using a ScheduledThreadPoolExecutor instead of a Timer.
Usage is pretty straight forward. You create an instance of an executor:
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor( 1 );
And then when you want to add a task you call:
executor.scheduleAtFixedRate( myRunnable, delay, interval, unit );
Where myRunnable is your task (which implements the Runnable-interface), delay is how long before the task should be executed the first time, interval is time between the execution of the task after first execution. delay and interval are meassured based on the unit parameter, which can be TimeUnit.* (where * is SECONDS, MINUTES, MILLISECONDS etc.).
Then to stop the execution you call:
executor.shutdownNow();
I develop a simple application and I use timer, but if I run the timer several times the timer drops this exception: Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already cancelled.
Here is my code:
public class Main {
...
private static void createAndShowUI() {
...
//a listener of a radio button
ActionListener on_action = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Timer.timer.schedule(Timer.task,0,2000); //I call the timer here
}
};
...
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
//and the class of timer:
public class Timer {
public static java.util.Timer timer = new java.util.Timer();
public static java.util.TimerTask task = new java.util.TimerTask() {
public void run() {
//some tasks
}
};
}
My question is that where I use the thread? Thanks!
The problem is not using the Event-Queue thread, it is that you are re-using a cancelled Timer.
I'm guessing you are using the Timer to do some animation or something in response to a button push (as you schedule things at a fixed rate). I'm guessing also that in code you don't show us, the timer gets cancelled by a separate event. If you ever call Timer.cancel() can you show us that code?
From the exception what is happening is that you are trying to use the same Timer that you have already cancelled. Once a Timer has been cancelled, it can't be used again.
Two suggestions - use a different Timer every time. Also, if you are doing things for UI purposes, you might want to consider using a Swing timer instead.
As far as the Thread goes, all GUI events happen on the AWT Thread, but I repeat, this is almost certainly not the problem. Read this for more details.
A timer goes into cancelled state if either the cancel() method has been invoked or the if the timer task has terminated unexpectedly:
If the timer's task execution thread terminates unexpectedly, for example, because its stop method is invoked, any further attempt to schedule a task on the timer will result in an IllegalStateException, as if the timer's cancel method had been invoked.
So in your case, it may not be a problem of where you put/call/use your time, but more a problem of what you're actually doing with your timer.
Here you have your thread:
Corresponding to each Timer object is a single background thread that is used to execute all of the timer's tasks, sequentially
so if you try to access your GUI from the Timer task you should put it into the EventQueue thread.
And look here
If the timer's task execution thread terminates unexpectedly, for example, because its stop method is invoked, any further attempt to schedule a task on the timer will result in an IllegalStateException, as if the timer's cancel method had been invoked.
Do you let the Timer schedule any more tasks after it has been cancelled?
I need to perform a task repeatedly that affects both GUI-related and non GUI-related objects. One caveat is that no action should performed if the previous task had not completed when the next timer event is fired.
My initial thoughts are to use a SwingTimer in conjunction with a javax.swing.SwingWorker object. The general setup would look like this.
class
{
timer = new Timer(speed, this);
timer.start();
public void actionPerformed(ActionEvent e)
{
SwingWorker worker = new SwingWorker() {
#Override
public ImageIcon[] doInBackground() {
// potential long running task
}
#Override
public void done() {
// update GUI on event dispatch thread when complete
}
}
}
Some potential issues I see with this approach are:
1) Multiple SwingWorkers will be active if a worker has not completed before the next ActionEvent is fired by the timer.
2) A SwingWorker is only designed to be executed once, so holding a reference to the worker and reusing (is not?) a viable option.
Is there a better way to achieve this?
For (1), the scheduleAtFixedRate() method on ScheduledThreadPoolExecutor might be useful. From the javadocs:
If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
For (2), it looks like you could define a subclass of SwingWorker and construct new instances of the subclass for each iteration, instead of instantiating an anonymous subclass.
Have you looked at using a simple Java Timer, and a ReadWriteLock to determine if a task is running when the timer triggers again ? In this situation you could simply bail out of that particular iteration and wait for the next.
Why do you use a Timer? It would be simpler to keep the 'worker' running all the time, pausing via sleep() whenever the task took too little time to complete. You can still update things in the event dispatch thread using something like the following:
Thread background = new Thread(new Runnable() {
public void run() {
while ( ! stopRequested ) {
long start = System.currentTimeMillis();
// do task
long elapsed = start - System.currentTimeMillis();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// update UI
}
});
if (elapsed < tickTime) {
Thread.sleep(tickTime - elapsed);
}
}
}
}.start();