0

I'm trying to make a countdown timer for a educational game that I'm creating (just for studying purposes), but I'm having a little problem.

Summarizing, I just need a timer that:

  • Make a 10 seconds countdown.
  • Stop when it reaches 0 seconds.
  • Throw an exception when it stop (that will be detected by my "View", to show a message to user).

My game have a lot of problems to be solved, each of them must be solved before 10 seconds. I've created a class called "Chronometer" for take care of the problems of my game, but I don't know how I can stop it and throw the desired exception (by the way, this is the best way to contact my view?).

Currently it counts from 10 to 0, but instead stop, it continues and next time it counts from 59 to 0 - and it never stop. How can I fix that?

Current code:

public class Chronometer {  

    private Timer chronometer;  
    private DateFormat format = new SimpleDateFormat("ss");  
    private Calendar calendar = Calendar.getInstance();  
    private final byte countType;  
    public static final byte PROGRESSIVE = 1;  
    public static final byte REGRESSIVE = -1;  

    public Chronometer(int years, int months, int days, int hours, int minutes, int seconds, byte countType) {  
        this.chronometer = new Timer();  
        calendar.set(years, months, days, hours, minutes, seconds);
        this.countType = countType;  
    }   

    public void starts_chronometer(){  
        TimerTask task = new TimerTask() {  
            public void run() {  
                System.out.println(getTime()); 
            }  
        };  
        chronometer.scheduleAtFixedRate(task, 0, 1000);  
        this.chronometer = null;  
    }  

    public int getTime() {  
        calendar.add(Calendar.SECOND, countType);  
        return Integer.parseInt(format.format(calendar.getTime()));
    }  
} 

Tried this to throw an exception:

(failed, it throws the exception at the same time chronometer starts.)

public void starts_chronometer() throws Exception {  
    TimerTask task = new TimerTask() {  
        public void run() {  
            System.out.println(getTime()); 
        }  
    };  
    chronometer.scheduleAtFixedRate(task, 0, 1000);  
    this.chronometer = null;  
    throw new Exception("The time's over!");
}  

Tried this to stop when reaches 0 seconds:

(failed, instead of 9...8...7...6 it works something like 9...6...5...3..1)

 public void starts_chronometer() {  
    TimerTask task = new TimerTask() {  
        public void run() {  
            System.out.println(getTime()); 
            if(getTime() == 0){
                chronometer.cancel();
            }
        }  
    };  
    chronometer.scheduleAtFixedRate(task, 0, 1000);  
    this.chronometer = null;  
}  

I already saw a lot of questions in StackOverflow about timers, but none of them help me solve my problem.

Please, help me solve this issue.

Paladini
  • 4,522
  • 15
  • 53
  • 96

2 Answers2

0

A great solution to this problem would be using the Observer pattern. With this pattern you have Observers and Observables. Observers can observe Observables (hence the name). The Obervable does not care if any Observer is observing him.

The solution I have made has two classes, the Main class (Observer) and the Chronometer class (Observable). The Main class adds itself as an Observer to the Chronometer object and the method void update(Observable, Object) will be ran when the Observerable has something to notify. The Chronometer is not using a Timer anymore. Instead it is using a Thread which will sleep for 10 seconds, after which it sets the state to modified and it notifies all Observers, thus calling the void update(Observable, Object).

With this implementation, the Chronometer will notify every Observer when it's done. This will allow you to know when the View has to be updated.

EDIT: I have changed the implementation of the run and update methods so the Observer is notified every second.

Main class:

public class Main implements Observer{

    public static void main(String[] args) {
        Main m = new Main();
        Chronometer c = new Chronometer(2014, 7, 4, 13, 46, 21, (byte) 0);
        c.addObserver(m);
        c.run();

        try {
            Thread.sleep(200000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void update(Observable arg0, Object arg1) {
        int time = (int)arg1;
        if(time > 0){
            System.out.println("Time left: " + time);
        } else {
            System.out.println("The time's over!");
            //Update View
        }
    }   
}

Chronometer:

public class Chronometer extends Observable implements Runnable{  

    private DateFormat format = new SimpleDateFormat("ss");  
    private Calendar calendar = Calendar.getInstance();  
    private final byte countType;  
    public static final byte PROGRESSIVE = 1;  
    public static final byte REGRESSIVE = -1;  

    public Chronometer(int years, int months, int days, int hours, int minutes, int seconds, byte countType) {    
        calendar.set(years, months, days, hours, minutes, seconds);
        this.countType = countType;  
    }   

    public int getTime() {  
        calendar.add(Calendar.SECOND, countType);  
        return Integer.parseInt(format.format(calendar.getTime()));
    }

    @Override
    public void run() {
        int time = 10;
        do {
            try {
                Thread.sleep(1000);
                setChanged();
                notifyObservers(time);
                time--;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } while (time >= 0);
    }  
}
Simon
  • 1,416
  • 1
  • 15
  • 24
0

Try this for stopping:

public class Chronometer {  

private Calendar calendar = Calendar.getInstance();
private static final long TIME_0 = -62167489199561L;
private final byte countType;  
public static final byte PROGRESSIVE = 1;  
public static final byte REGRESSIVE = -1;  

public Chronometer(int years, int months, int days, int hours, int minutes, int seconds, byte countType) {  
    calendar.set(years, months, days, hours, minutes, seconds);
    this.countType = countType;  
}   

public void startChronometer(){
    Timer t = new Timer();
    TimerTask task = new TimerTask() {  
        public void run() {  
            System.out.println(getTime());
            if(getTime()==0) throw new RuntimeException("Done");

            calendar.add(Calendar.SECOND, countType); 
        }  
    };  
    t.scheduleAtFixedRate(task, 0, 1000);  
}  

//Returns seconds left  
public long getTime() {  
    return Math.round((calendar.getTime().getTime()-TIME_0)/1000);
}  

public static void main(String[] args) {
    Chronometer c = new Chronometer(0, 0, 0, 0, 0, 10, REGRESSIVE);
    c.startChronometer();
}
} 
Teddy
  • 4,009
  • 2
  • 33
  • 55
  • And this never finish too :P – Paladini Jul 04 '14 at 20:58
  • It works ok... pls check. This is the output in Eclipse: 9 8 7 6 5 4 3 2 1 0 Exception in thread "Timer-0" java.lang.RuntimeException: Done at com.test.so.Chronometer$1.run(Chronometer.java:29) at java.util.TimerThread.mainLoop(Unknown Source) at java.util.TimerThread.run(Unknown Source) – Teddy Jul 04 '14 at 21:03