Reputation: 467
I start a timer when the first question appears, it goes back. If the user answers the question in time, I want timer to completely cancel and a new timer to start. However, when user answers the question, in the second question, the first timer still process.
This is my timer method:
public Timer myTimer() {
timer = new Timer();
timerTask = new TimerTask() {
@Override
public void run() {
sec--;
if (sec<0) {
this.cancel();
game.dispatchEvent(new WindowEvent(game, WindowEvent.WINDOW_CLOSING));
JOptionPane.showMessageDialog(null, "GAME OVER!\nYour score: " + score);
scoreJSON = new ScoreJSON(playerName, score);
scoreJSON.write();
} else if (sec<10) {
time.setText("0" + String.valueOf(sec));
} else {
time.setText(String.valueOf(sec));
}
}
};
timer.schedule(timerTask, 1000, 1000);
return timer;
}
This is one alternative for user to answer the question:
a.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
checkAnswer("answer0");
myTimer();
}
});
Upvotes: 0
Views: 177
Reputation: 757
I reworked your myTimer()
method and found that calling cancel()
on the Timer
instance (instead of the TimerTask
) correctly stops the Timer. This happens because invoking cancel()
on the TimerTask
may cancel the task, but not the timer. The below code shows the class I used to test with.
public class TimerTest {
public static final int TIMEOUT = 5;
private static Timer timer;
public static void main(String[] args) {
// Creates and starts the Timer. The TimerTask cancels the Timer when
// it's done, so we don't need to keep a reference to it.
timer = myTimer(TIMEOUT);
try {
// Suppose the correct answer is given after 2.5 seconds
Thread.sleep(2500);
} catch (InterruptedException e) {
}
timer.cancel();
System.out.println("Timer interrupted by main");
}
public static Timer myTimer(final int timeout) {
// We keep the Timer instance with the TimerTask, to prevent us from
// having to worry about managing multiple timers. Each Timer is
// guaranteed to stop when sec drops to 0.
final Timer t = new Timer();
TimerTask timerTask = new TimerTask() {
// We keep the current time in each TimerTask. This ensures that
// multiple TimerTasks will not interfere with each other.
private int sec = timeout;
@Override
public void run() {
sec--;
if (sec < 0) {
t.cancel(); // cancel the Timer here.
System.out.println("Timer stopped by TimerTask");
} else {
// Replace this with whatever you do each second
System.out.println("Current time: " + (sec < 10 ? "0" : "") + sec + " seconds");
}
}
};
t.schedule(timerTask, 1000, 1000);
return t;
}
}
Running the example starts a Timer, and then stops it after 2.5 seconds (this also exits the JVM, as there are no more running Threads). Changing t.cancel()
in the TimerTask to this.cancel()
seems to cancel the task (nothing is printed anymore), but fails to cancel the timer (the JVM keeps running).
Upvotes: 1
Reputation: 2321
You need to have a way to safely stop the thread. Check out this option: The Safe Way to Stop a Thread by Bruce Eckel. This way you can call requestStop on the timer thread that's running, then start a new thread. You will have to save a reference to every timer thread you kick off so you can call the .requestStop method on it later.
Upvotes: 0