I am trying to schedule a repeating timer in GWT, it will run every one milli second, poll for a certain event, if it is found satisfactory, do something and cancel the timer.
I tried doing this:
final Timer t = new Timer() {
public void run() {
if (..condition is true, exit) {
t.cancel();
doSomething();
}
}
}
t.scheduleRepeating(1);
However, I get an error message like the local variable t may not have been initialized. I am putting tis piece of code in the onSuccess clause of a RequestBuilder callback.. How do I achieve this?
You cannot access it while intializing itself.
change your code to
final Timer fgf = new Timer() {
#Override
public void run() {
cancel();
System.out.println();
}
};
Related
I am trying to build more or less a watchdog class. If a value hasn't changed for a certain time, the class should do something.
Therefore I want to utilize a standard timer, the idea is to set a timer, and reset it as soon as the watched value changes.
public class Watchdog {
public final Timer TIMER = new Timer(true);
public final long DELAY;
public Watchdog(long delay){
DELAY=delay;
valueChanged();
}
public void valueChanged(){
TIMER.cancel();
TIMER.purge();
TIMER.schedule(new TimerTask() {
#Override
public void run() {
Watchdog.this.alarm();
}
}, DELAY);
}
public void alarm(){
System.out.println("Watchdog barked");
}
}
Unfortunately I get an IllegalStateException every time I call TIMER.cancel(), as there is no timer set at the first call. What am I doing wrong? How to reset the timer, even if there is no timer set?
EDIT
Stacktrace
Exception in thread "main" java.lang.IllegalStateException: Timer already cancelled.
at java.util.Timer.sched(Timer.java:397)
at java.util.Timer.schedule(Timer.java:193)
at deleteme.Watchdog.valueChanged(Watchdog.java:28)
at deleteme.Watchdog.<init>(Watchdog.java:22)
at deleteme.Deleteme.main(Deleteme.java:19)
Java Result: 1
According to the Timer source code, the cancel method changes the value of an internal flag called newTasksMayBeScheduled to false.
public void cancel() {
synchronized(queue) {
thread.newTasksMayBeScheduled = false;
queue.clear();
queue.notify(); // In case queue was already empty.
}
}
The value of this flag is checked prior to scheduling a new task and it fires the exception you get as it is false.
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
I think that you should use the cancel method of the TimerTask instead of Timer.
For the sake of completeness of the answer, note that an alternative would be to use ScheduledThreadPoolExecutor.
I have a window, with a Start- and Stop-Button. The Start-Button starts the algorithm and the stop-button should stop it. I use SwingWorker do run the algorithm in the background and normally calling worker.cancel(true) should stop the algorithm running. I also have a Label, that visualize the Status, e.g. if I press "Stop", then the Labeltext changes to "stopped", so the Problem isnt on the actionLister of the Button.
My code looks like this:
public class MainWindow extends JFrame implements ActionListener, WindowListener
{
// Some code, like generating JFrame, JButtons and other stuff not affencting the task.
Worker worker = new Worker();
public void actionPerformed(ActionEvent e)
{
boolean isStarted = false;
// Start Button
if (e.getSource() == this.buttonStart)
{
if(!isStarted)
{
System.out.println("start");
labelSuccess.setText("Mapping started!");
this.setEnabled(true);
worker.execute();
isStarted = false;
}
}
// Stop Button
if (e.getSource() == this.buttonStop)
{
labelSuccess.setText("Mapping stopped!");
worker.cancel(true);
}
}
class Worker extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() throws Exception {
if(!isCancelled())
{
mapp();
Thread.sleep(60);
if (isCancelled()) {
System.out.println("SwingWorker - isCancelled");
}
}
return null;
}
}
At this Point, pressing the Stop-Button causes just a change of the Label-Text, but the algorithm in the background is still running. This now bothers me for quite a while and I just can't get it going.
Thanks a lot for any help, much appreciated.
edit1: I generate a new instance of worker now outside of actionPerformed, so now there is no new Worker generated on every mouse click.
Maybe if you use while instead of if on doInBackground() method of Worker class you will solve your problem. You must to put out of the while loop the mapp(), because you only want to invoke it one time. You should do something like this:
class Worker extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() throws Exception {
mapp();
while(!isCancelled()){
Thread.sleep(60);
}
System.out.println("SwingWorker - isCancelled");
return null;
}
This link could be useful to understanding how to use SwingWorker.
EDIT:
As you can see on another questions like this or this, using SwingWorker has some problems to manage the cancel method, because this method Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason, like Oracle explains, and those "some other reasons" are discussed on the links I've posted.
You can do solve your problem using directly Threads. Your code would be something like this:
public class MainWindow extends JFrame implements ActionListener, WindowListener
{
// Some code, like generating JFrame, JButtons and other stuff not affencting the task.
final Thread th1 = new Thread(new Runnable() {
#Override
public void run() {
mapp();
}
});
public void actionPerformed(ActionEvent e)
{
boolean isStarted = false;
// Start Button
if (e.getSource() == this.buttonStart)
{
if(!isStarted)
{
System.out.println("start");
labelSuccess.setText("Mapping started!");
this.setEnabled(true);
th1.start();
isStarted = false;
}
}
// Stop Button
if (e.getSource() == this.buttonStop)
{
labelSuccess.setText("Mapping stopped!");
th1.stop();
}
}
This solutions uses the method stop(), which is deprecated, but it works. I've tried using interrupt(), but I don't know why the thread ran till finish the execution of mapp(). Obviously, using stop() is not the best method but it works stopping the mapp() execution before it finishes.
I recommend you to learn more about SwingWorker, Thread and Task to find the best solution to your problem.
Your problem is there is no loop in the worker: if you want to cancel a process using a flag, that process should check the flag from time to time, so if your method Worker.mapp() has to be stopped, check the flag there, no just before and after calling it.
I have scheduled a method to run at a certain date in the future; however, there are certain events that may or may not happen before that date that would mean I want to run the method earlier than the specified date; how can I do this? I currently have:
Timer timer = new Timer();
TimerTask task = new TaskToRunOnExpriation();
timer.schedule(task, myCalendarObject.getTime());
I will have many of these TimerTask's running in my application, stop specific instances of them if a certain even happens?
EDIT
I will only ever want to cancel a single Timer for a given event, is there a way of managing the identities for the Timers such that I can easily find and stop it?
If you have thousands of them you should use a ScheduledExecutorService which will pool threads rather than a Timer which will use one thread per timer.
The ScheduledFutures returned by the executor service when you schedule a task also have a cancel method to cancel the underlying tasks: future.cancel(true);.
As for cancelling the right task, you could store the futures in a Map<String, Future> so you can access them by name or id for example.
In C# I would say use delegates, but that is not an option in Java. I would work off this idea:
class Timers
{
Timer timer1;
Timer timer2;
ArrayList<Timer> timerList;
public Timers()
{
// schedule the timers
}
// cancel timers related to an event
public void eventA()
{
timer1.cancel();
timer2.cancel();
}
public void eventB()
{
for(Timer t : timerList)
t.cancel();
}
}
Use this schedule method.
public void schedule(TimerTask task,Date firstTime,long period)
task--This is the task to be scheduled.
firstTime--This is the first time at which task is to be executed.
period--This is the time in milliseconds between successive task executions
I use Timer in android to update a progress bar.Here is some of my code, hoping it can help you:
Timer timer ;
#Override
protected void onCreate(Bundle savedInstanceState) {
//....
timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
updateLogoBarHandler.sendEmptyMessage(0);
Log.e("SplashActivity","updating the logo progress bar...");
}}, 0, 50);
//.....
}
//here do the timer.cancel();
private Handler updateLogoBarHandler = new Handler() {
public void handleMessage(Message msg) {
if(logobarClipe.getLevel() < 10000){
logobarClipe.setLevel(logobarClipe.getLevel() + 50);
}else{
timer.cancel();
}
super.handleMessage(msg);
}
};
After creating a session, i want to call a method again & again after a specific time - i.e. 5 sec.
But when i call a method it gives me an error. Here is the sample code.
public class RunFunction extends MainScreen{
public RunFunction()
{
//Call Function again and again after 5 sec
setTitle("Timer");
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
BasicEditField b = new BasicEditField("Hello", "");
String a = b.getText();
Dialog.alert("Value " +a);
}
}, 5000);
}
}
I need help related to this. Can you provide any sample code?
From the BlackBerry docs on the Timer class:
A facility for threads to schedule tasks for future execution in a background thread.
So, the first thing to understand is that whatever work you do in the run() method will be run on a background thread. Background threads are not allowed to modify the UI directly. You're probably getting an IllegalStateException by doing that.
Maybe this is just test code, but this code
BasicEditField b = new BasicEditField("Hello", "");
String a = b.getText();
Dialog.alert("Value " +a);
is a little confusing. It creates a BasicEditField, but only uses it to get the String value passed in to it. Just instantiating a field does not add it to a screen. So, you would need to call
add(b);
after this code for the edit field to show. But again, that would be modifying the UI directly. So, in your case, you probably just need to wrap your code with a call to UiApplication#invokeLater():
timer.schedule(new TimerTask() {
public void run() {
// this code executed on background thread -> not UI safe!
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// this code safely executed on UI thread
BasicEditField b = new BasicEditField("Hello", "");
add(b);
String a = b.getText();
Dialog.alert("Value " +a);
}
});
}
}, 5000);
Next, calling Timer#schedule(TimerTask,long) will only schedule your task to run once, after 5000 milliseconds. If you want it to run again and again, use the version of schedule(TimerTask,long,long) that takes three parameters. The last parameter is the amount of time between each call to your timer task's run() method.
This example on Timer and TimerTask java class provides some insights on what you want to do:
http://javaprogramming.language-tutorial.com/2012/02/demonstrate-timer-and-timertask.html
My CheckStatus (TimerTask) is not stopping when I call cancel() inside the run method. this.cancel() also does not work. What am I doing wrong?
import java.util.TimerTask;
class CheckStatus extends TimerTask {
int s = 3;
public void run() {
if (s > 0)
{
System.out.println("checking status");
s--;
}
else
{
System.out.println("cancel");
cancel();
}
}
}
Heres my driver
import java.util.*;
class Game {
static Timer timer;
static CheckStatus status;
public static void main(String[] args) throws InterruptedException {
CheckStatus status = new CheckStatus();
timer = new Timer();
timer.scheduleAtFixedRate(status, 0, 3000);
}
}
It works for me - using exactly the code you posted, I saw:
checking status
checking status
checking status
cancel
... and nothing else, showing that the TimerTask has been cancelled - it's never executing again.
Were you expecting the Timer itself to shut down when it didn't have any more work to do? It doesn't do that automatically. It's not clear what your bigger goal is, but one option to avoid this is to make the TimerTask also cancel the Timer - that will work, but it's not terribly nice in terms of design, and means that the TimerTask can't run nicely within a timer which contains other tasks.
you are calling the cancel method of the timer task but you should call the cancel method of the timer itself to get your expected behaviour.