I'm making an Android app that turns on/off the flash light after a specified interval, by the user. It works well except when the Timer object is re-created after calling the .cancel() method for the second time, it crashes the app every time.
Here's the initialization part:
Timer timer; //variable of Timer class
TimerTask timerTask; //variable of TimerTask class
And here's the method that is called when the button responsible to turn blinking on/off is pressed:
blink.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
delay = Integer.valueOf(startDelay.getText().toString());
gap = Integer.valueOf(blinkDelay.getText().toString());
if(!isBlinking) { //isBlinking is a boolean to know whether to stop or re-start timer
timer = new Timer(); //I'm creating an object of Timer class every time.
isBlinking = true;
timer.schedule(timerTask, delay, gap);
}
else{
isBlinking = false;
stoptimertask(); //this will cancel the 'timer' and make it null.
}
}
});
The 'stoptimertask()' method from above code has:
public void stoptimertask() {
//stop the timer, if it's not already null
if (timer != null) {
timer.cancel();
timer = null;
}
}
I'm setting the 'timertask' variable of TimerTask class from the method shown below. It is called in the onCreate() method of the main activity:
public void initializeTimerTask() {
timerTask = new TimerTask() { //This is passed as the first argument to the timer.schedule() method
public void run() {//Basically turns on/off flash. Works well.
if(!state) {
turnOnFlash();
state = true;
}
else {
turnOffFlash();
state = false;
}
}
};
My question is that why does the app crash when I press the blink button the third time?
When it is pressed for the first time, isBlinking is false, so the if block executes creating a new object of the Timer class and starting the timer.
When it is pressed for the second time, stoptimertask() is called which cancels the timer and sets timer variable to null.
When it is pressed again for the third time with different values for delay and gap, a new object of Timer class should be created, but the application crashes unexpectedly with a "Unfortunately the app has stopped" error.
Where am I going wrong?
You will have to purge as well.
timer.cancel();
timer.purge();
Don't forget to purge after cancel.
Your code must be for stoptimertask() method.
public void stoptimertask() {
//stop the timer, if it's not already null
if (timer != null) {
timer.cancel();
timer.purge();
timer = null;
}
}
Related Link:
Android timer? How-to?
How to set a timer in android
UPDATE:
Since Timer creates a new thread, it may be considered heavy,
if all you need is to get is a call back while the activity is running a Handler can be used in conjunction with this link
How to set a timer in android
Related
I have a JButton that starts a countdown timer when pressed. When I press the button, it begins, and when I press it again (Button will say "Stop"), it stops. However when I press it again to start the time again I get an error saying:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already cancelled.
Here is my code:
final static Timer t = new Timer();
static void startTimer(JButton b) {
t = new Timer(); // Solved: I needed to create a new Timer object.
t.scheduleAtFixedRate(new TimerTask() {
double timeleft = calcShutterSpeed;
#Override
public void run() {
String s = secondsToMinutes(timeleft);
time.setText(s);
timeleft--;
if (timeleft < 0) {
t.cancel();
b.setText("START TIMER");
b.setForeground(Color.BLACK);
}
}
}, 0, 1000);
}
static void stopTimer() {
t.cancel();
}
/**
* Creates the timer if "Start" is pressed.
*
* #param b
*/
static void timer(JButton b) {
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// If start button is pressed, change text to display stop
if (b.getText() == "START TIMER") {
startTimer(b);
b.setText("STOP TIMER");
b.setForeground(Color.RED);
}
// If stop button is pressed, cancel timer and change text to start
else if (b.getText() == "STOP TIMER") {
stopTimer();
b.setText("START TIMER");
b.setForeground(Color.BLACK);
}
}
});
}
Any tips or suggestions that can fix this problem would be much appreciated. Thanks in advance!
EDIT: Really really simple fix for the curious. The fix is in the code.
I think that the "cancel" method on timer still keeps scheduled task with a cancel status.
The call to "purge" method, directly after the cancel should clean the queue and maybe solve this issue.
I have a method called timer that I run everytime a user inputs something and the timer is scheduled for a minute, but I want the timer to cancel if the user enters something in less than a minute and then recall itself so the whole process happens again. My methods are below:
Input method
public static String run(){
timer(); //runs everytime I call run()
String s = input.nextLine();
return s;
}
Timer method
public static void timer() {
TimerTask task = new TimerTask() {
public void run() {
System.out.println("Times up");
}
};
long delay = TimeUnit.MINUTES.toMillis(1);
Timer t = new Timer();
t.schedule(task, delay);
}
method run() keeps getting called everytime someone inputs something so timer keeps getting called but that doesn't stop the previous timers though, I want the timer to stop, then recall itself so that problem doesn't exist. Anyone know a way?
The TimerTask class has a method called cancel() which you can call to cancel a pending timer.
In your code, you will probably need to modify your timer() function to return a reference to the newly created TimerTask object, so that you can later call cancel().
I'm developing a game where LittleMan can move from block to block, and certain blocks are moving. I'm trying to detect when he moves to a new moving block, if that block is beneath him or if it has moved. I'm using Andengine's TimerHandler to check every 0.1 seconds but it is not working. Here's the code:
private void OnMovingBlock(final int CurrentPosRow, final int CurrentPosColumn) {
this.getEngine().registerUpdateHandler(new TimerHandler(0.1f, true, new ITimerCallback() {
#Override
public void onTimePassed(final TimerHandler pTimerHandler) {
if (LittleManPos[0] == CurrentPosRow && LittleManPos[1] == CurrentPosColumn) {
if (!LittleMan.collidesWith(MapRectangles[CurrentPosRow][CurrentPosColumn])) {
RestartScene();
}
}
}
}));
}
It seems he can move to the block and sit there with it moving in and out beneath him but it doesn't call RestartScene() UNTIL I move him again. Any idea where I am going wrong? Or is there another way to do this?
Why don't create a Timer?
TimerTask task = new TimerTask(){
#Override
public void run(){
// your code goes here
}
};
Timer timer = new Timer();
timer.sechedule(task, 0, 100); // 100 --> 0.1 second
To cancel the Timer, call timer.cancel();.
I need to make a GUI where a worker enters a station (a spot on the panel) and stays there for a set amount of seconds, shown in a countdown about the workers head (so, once the workers moves to the spot, the station's label shows 3s -> 2s -> 1s and then the worker leaves, and the label reverts back to "OPEN"). I'm having trouble with making this happen, as I'm not too good with the Timer(s?) that Java has. I tried with something like this:
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
//change label text/color, decrement countdown
panel.repaint();
Thread.sleep(1000);
}
});
But I can't reach the number of seconds to count down from from inside the timer, and I'm not sure how to pass that value to the timer. If someone can help me out, I'd really appreciate it.
Get rid of the Thread.sleep(). That's what the 1000 in Timer(1000, new ActionListener() does. It sets an interval for each timer event. Every time a timer event is fired, the actionPerformed is called. So you need to determine what needs to happen every "tick", and put that code in the actionPerformed. Maybe something like
Timer timer = new Timer(1000, new ActionListener() {
private int count = 5;
#Override
public void actionPerformed(ActionEvent e) {
if (count <= 0) {
label.setText("OPEN");
((Timer)e.getSource()).stop();
count = 5;
} else {
label.setText(Integer.toString(count);
count--;
}
}
});
You need to decide when to call timer.start().
For general information, see How to Use Swing Timers
Problem #1: You are calling Thread.sleep() from within the Swing GUI thread. That causes the thread to stop taking input and freeze. Delete that line. It does you no good! While you are at it, delete the repaint call as well.
Now that that's said and done, instead of creating an anonymous instance of ActionListener, you can create an actual class that implements ActionListener and provides a constructor. That constructor can have as an argument the number of seconds you want to start counting down. You can declare that class inside the method you are using, or you can declare it inside the class.
Here's a skeletal example:
public class OuterClass {
JLabel secondsLabel = ...;
Timer myTimer;
private void setupTimer(int numSecondsToCountDown) {
secondsLabel.setText(Integer.toString(numSecondsToCountDown));
myTimer = new Timer(1000, new CountdownListener(numSecondsToCountDown));
myTimer.start();
}
// ...
class CountdownListener implements ActionListener {
private int secondsCount;
public CountdownListener(int startingSeconds) { secondsCount = startingSeconds; }
public void actionPerformed(ActionEvent evt) {
secondsLabel.setText(Integer.toString(secondsCount);
secondsCount--;
if (secondsCount <= 0) { // stop the countdown
myTimer.stop();
}
}
}
}
I'd like to accomplish something which I would think to be simple, but is turning out to be a hassle.
I have a loading screen with a picture, and I'd like for it to fade in and out as the application is loading. I decided to accomplish this by changing it's opacity frequently relative to the sine value of a counter. My code is as follows:
ImageView loadingRaven; //loading raven at the start of the app
Timer timer; //timer that we're gonna have to use
int elapsed = 0; //elapsed time so far
/*
* the following is in the onCreate() method after the ContentView has been set
*/
loadingRaven = (ImageView)findViewById(R.id.imageView1);
//fade the raven in and out
TimerTask task = new TimerTask()
{
public void run()
{
elapsed++;
//this line causes the app to fail
loadingRaven.setAlpha((float)(Math.sin(elapsed)+1)/2);
}
};
timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 50);
What is the problem that's causing my program to fail? Am I correctly using Timer and TimerTask? Or is there perhaps a better way to update the opacity of the image frequently so it eases in and out smoothly?
Thanks
TimerTask runs on a different thread. So update ui on the main ui thread. Use runonuithread
TimerTask task = new TimerTask()
{
public void run()
{
elapsed++;
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
loadingRaven.setAlpha((float)(Math.sin(elapsed)+1)/2)
}
});
}
};
TimerTask runs on a different thread. You can use Handler and postDelayed as suggested by
pskink