I need a way to have a timer that is running on start command. Initially, the timer will be told how long to run for. However, i need a way to change this mid-way in between. If a user specifies that they would like to change the time the timer runs (by either decreasing, increasing or even ending the timer all together). I also want to be able to update the UI by showing the current time in minutes:seconds format.
The user may also want to spawn multiple timers - so they should have a way of monitoring and accessing different timers which they have set..
Currently this is what i have - from what i can tell, it works.. but i don't feel too good about it :S how can i make this better? Or what is the right way of doing this? Keep in mind that there will be other things happening while this timer is running - for instance, the user may be interacting with the UI and executing different commands un-related to the timer..
I really don't know much about threads or threading... so this is relatively new to me..
thanks in advance!
In Main:
//every time they request for a new timer, i will instantiate a new Task object..
Task task = new Task();
task.run()
task.getTaskTime();
Task.java:
public class Task extends Thread{
#Override
public void run()
{
timer = new Timer(60 * 60);
timer.start();
}
public boolean getTImerRunning() {
return timer.timerRunning;
}
public double getTaskTime() {
return timer.currentTime;
}
}
In Timer.java:
public class Timer extends Thread {
public static final int DEFAULT_TIMER = 180;
private long startMinute = 0;
private int _timer;
public double currentTime = 0;
public boolean timerRunning = true;
Timer(int timer) {
this._timer = timer;
}
Timer() {
this._timer = DEFAULT_TIMER;
}
#Override
public void run(){
long start = System.currentTimeMillis();
startMinute = start;
while(elapsedTime() <= this._timer) {
currentTime = elapsedTime();
}
timerRunning = false;
}
/**
* Return elapsed time since this object was created.
*/
private double elapsedTime() {
long now = System.currentTimeMillis();
return (now - startMinute);
}
}
Every time the user creates a "timer", do not create a new Task, but create an object MyTimer that holds the creation time and countdown duration and add the instance to an ArrayList.
The very first and only the first time, a user creates a timer you will create a task that executes every second. When that task executes it updates the UI and cycles through the ArrayList and updates each instance of MyTimer by adjusting the countdown duration.
That should keep things simple and reduce overhead.
Good Luck!
Related
I am trying to build multiple Timers and scheduled independent tasks for each of them. I have a constructor for holding a Timer and its variable. Then, I will call them one by one but I found that the variables, passed to the Timer constructor, are overrode by each other. I already initiate each Timer as a new instance but still cannot solve the issue. How can I make sure the timers are run independently?
Code:
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
TimerTrigger.INSTANCE.runTimer();
}
}
To Trigger the timer:
public enum TimerTrigger {
INSTANCE;
private TimerTrigger(){}
public void runTimer(){
for (int i = 0; i < 3; i++) {
System.out.println( "Initiaizing Timer " + i );
TimerConstructor tmpTimer = new TimerConstructor();
varObjectvo timerVariable = new varObjectvo();
timerVariable.setIndex(i);
// timerList.add(tmpTimer);
tmpTimer.start(timerVariable); //timerVariable is a value object
}
}
}
The Constructor of timer:
import java.util.Timer;
import java.util.TimerTask;
import java.util.Date;
public class TimerConstructor{
private static varObjectvo timerVO = null;
Timer timer = null;
public void start(varObjectvo obj) {
timer = new Timer("Timer_" + obj.getIndex()); // will be Timer_1/2/3
timerVO = obj;
TimerChecker task = new TimerChecker();
timer.scheduleAtFixedRate(task, new Date(), 10000);
}
private class TimerChecker extends TimerTask {
public void run() {
System.out.println("It is timer " + timerVO.getIndex() + " from: " + timer.toString());
}
}
}
The value object class:
public class varObjectvo{
private Integer index;
public void setIndex(Integer i){
this.index = i;
};
public Integer getIndex(){
return this.index;
};
}
Output:
Hello World!
Initiaizing Timer 0
Initiaizing Timer 1
It is timer 0 from:java.util.Timer#6b45c377
It is timer 1 from:java.util.Timer#17481b7c
Initiaizing Timer 2
It is timer 2 from:java.util.Timer#48e94d09
It is timer 2 from:java.util.Timer#17481b7c
It is timer 2 from:java.util.Timer#48e94d09
It is timer 2 from:java.util.Timer#6b45c377
In short, seems the variables in former Timer are being overwritten by the later Timer.
As commented, your main problem seems to be making your variable timerVO static.
The static keyword means you want only one such value rather than each instance having its own value known by that name. In other words, static is not object-oriented.
So each time you execute timerVO = obj;, you replace the previously stored value with the current one. You have only a single timerVO in your entire app, because you marked it static. That timerVO can contain only a single value, the value last assigned.
You said:
I already initiate each timer as new instance but still cannot solve the issue.
But… all those timer objects you instantiated share the same single static timerVO object.
Minor issue: Class names start with an uppercase letter. So public class varObjectvo should be public class VarObjectvo.
Another minor issue: Naming a method “…Constructor” is confusing. That word has a very specific crucial meaning in Java. A constructor in Java is always named the same as the class name.
Bigger picture: You are not taking advantage of modern Java. If you read carefully the Javadoc of Timer and TimerTask classes, you’ll see they were supplanted years ago by the Executors framework.
To use executors, define your tasks as implementing either Runnable or Callable. Then establish a ScheduledExecutorService. Submit instances of your tasks to that service for repeated execution.
Search Stack Overflow to learn more. Scheduled executor service has been covered many many times already.
Some rough untested code follows.
class Counter implements Runnable {
private final AtomicInteger count = new AtomicInteger( 0 ) ;
void run() { this.count.incrementAndGet() ; }
int getCount() { return this.count.get() ; }
}
Instantiate.
Counter countEvery5Seconds = new Counter() ;
Counter countEvery42Seconds = new Counter() ;
Initialize your scheduled executor service.
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor() ;
Schedule your tasks.
ScheduledFuture<?> count5 =
scheduler.scheduleAtFixedRate( countEvery5Seconds, 0, 5, TimeUnit.SECONDS);
ScheduledFuture<?> count42 =
scheduler.scheduleAtFixedRate( countEvery42Seconds, 0, 42, TimeUnit.SECONDS);
Be sure to shutdown your executor service. See discussions in many other Answers. See boilerplate code in Javadoc.
The tile does not describe it properly so im going to try and describe it here:
I have a bukkit plugin, its a minigame.
It must have some code run for 10 minutes and then run another code until that game is finished
I currently have this:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
// code for 10 minutes
}
}, 600000);
//code for after
Yet, this is only affects a single player and not that world.
So if one player joins he will wait 10 minutes and then run the otherpart of the code and so on, when the purpose is the 10 minutes start couting on their own, even if there is no player.
Thanks
Your problem is probably caused because your code is all triggered by an event?
Meaning it will only ever effect the player that triggered that event.
Instead you need a generic plugin that does not trigger on events (except for login), but instead it uses a timer and then grabs a list of all players and runs your code on each/all of them. Then after 10min it will exit to your other code and run that for the rest of the time.
Edit: rough example:
import org.bukkit.plugin.java.JavaPlugin;
public final class {$PluginName} extends JavaPlugin {
#Override
public void onEnable() { //This should proberbly be done onCommand rather than onEnable
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
long time = System.currentTimeMillis();
while (some condition....){
//load list of players
//now iterate through player list and do your code
//check if 10min has passed:
if ((System.currentTimeMillis() - time) > 600000){
//now break the loop and run your other code for the rest of the minigame
break;
}
}
//code for the rest of the minigame
while (true){
//load list of players
//now iterate through player list and do your code for the rest of the time
}
}
});
thread.start();
}
}
I want to generate random number after every 2 seconds in my java (Android) program continuously for at least 10 minutes. But I just want to pause/delay execution of code in only one method and not the whole program.
I tried using Thread like this -
boolean stop = false;
int random_number = 0;
while(true){
if(stop){ //if stop becomes true, then
return; //terminate the method
}
random_number = Math.random(); //generate random number
//which is used bu some other
//part of code
try {
Thread.sleep(2000); //delay the code for 2 secs
} catch(InterruptedException ex) { //and handle the exceptions
Thread.currentThread().interrupt();
}
}
However, this doesn't work as Thread.sleep stop the whole program execution instead on just stopping execution of code inside method and my whole screen becomes blank.
I also tried using Handler but it didn't work either as it doesn't stop execution of code in my method and instead just stack up.
This will demonstrate the working of it better -
while(true){
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
System.out.println("After 2 secs"); //this gets printed
//later
}
}, 2000);
System.out.println("Before 2 secs"); //this gets printed first
}
So the code stacks up making it equivalent to using while loop and make it incredibly slow.
Also, since I'm developing app for Android, I'm running on Java SE 6, so I can't use scheduleAtFixedRate. Is there any other way in which I can accomplish this?
Thanks a lot!
private Timer timer;
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//Generate number
}
}, 2000, 2000);
//Documentation (From SDK)
/**
* Schedule a task for repeated fixed-rate execution after a specific delay
* has passed.
*
* #param task
* the task to schedule.
* #param delay
* amount of time in milliseconds before first execution.
* #param period
* amount of time in milliseconds between subsequent executions.
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
if (delay < 0 || period <= 0) {
throw new IllegalArgumentException();
}
scheduleImpl(task, delay, period, true);
}
and when you want to stop it
timer.cancel()
Option 1: Using threads, you might run your job off the main (UI) thread:
new Thread(new Runnable() {
// some code here ...
// This might be in a loop.
try {
Thread.sleep(2000);
} catch(InterruptedException ex) {
// Handle ...
}
}
}).start();
Then, if this new thread you'd like to modify UI (i.e. show/hide button, display something on the screen etc), remember to pass that through the UI thread, as only this one can modify the UI. You might consider using Activity.runOnUiThread() for that.
Option 2: Another, more Android-style way of approaching that issue is to use AsyncTask. It contains three callbacks which can be used to do work on- and off- the UI thread. Sketch of such a code could look like:
private class MyTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... param) {
// This method is running off the UI thread.
// Safe to stop execution here.
return null;
}
protected void onProgressUpdate(Void... progress) {
// This methid is running on the UI thread.
// Do not stop thread here, but safe to modify the UI.
}
protected void onPostExecute(Long result) {
// Also on UI thread, executed once doInBackground()
// finishes.
}
}
Option 3: Then there is also a Timer, as suggested by #Stultuske. It's less flexible then AsyncTask, but handles the interval for you.
Depending on your needs, you can still accomplish what you seek with Handler.
You don't have to create/start the Handler in a while loop(which, as you noticed, just stacks up unless you stop the loop itself, but it is a nonsense).
Just create the Handler and tell him to post delayed your Runnable instance. In the Runnable at the very end you check your conditions. If it is still OK, then post another runnable delayed, else you do nothing and the Handler will have no more executions.
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
System.out.println("After 2 secs");
random_number = Math.random();
if (!stop) // should not be stopped, so we add another runnable;
{
handler.postDelayed(this, 2000);
}
}
handler.postDelayed(runnable, 2000);
The only downside is that Handler could freeze if the device is not used for a while, meaning it will start the counting back from where it left once the device screen is turned on.
It could do like 1 minute of correct work, then block at 1.4 seconds when the device is gone in sleep mode, and once it is turned on again, Handler would do the remaining 0.6 seconds.
Still, not knowing your needs you may be unaffected by this behavior and the answer may fit you.
if you want to use thread, do it like this :
Thread t = new Thread(){
public void run(){
while(true){
if(stop) break;
random_number = Math.random();
sleep(2000);
}
}
};
t.start();
For my MIDI player, I wanted to print 10 times in a second to get an accuracy of the timing but, the program consume quite a large amount of memory, how do I fix the code?
public void tick(int seconds) {
timer = new Timer();
timer.schedule(new tickcount(), seconds * 100);
}
class tickcount extends TimerTask {
public void run() {
if(sequencer != null) {
System.out.println("sec"+sequencer.getMicrosecondPosition()/1000000);
timer = null;
tick(1);
} else {
timer.cancel();
}
}
}
I don't really see how this code could be causing any kind of large memory consumption, unless it has to do with the incredible rate at which it'll be creating new threads.
At any rate, you should use a ScheduledExecutorService... Timer is kind of outdated (though even using it, you shouldn't be creating a new Timer each time your task runs). If you want the code in your tickcount task to run once every 0.1 seconds, you could do it like this:
private final ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor();
private Future<?> timingTask;
public void tick(long milliseconds) {
timingTask = scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("sec"+sequencer.getMicrosecondPosition()/1000000);
}
}, 0, milliseconds, TimeUnit.MILLISECONDS);
}
Here, the tick method will start your timer running, calling the Runnable every milliseconds ms, starting immediately. It also assigns a Future<?> to a field... this allows you to call timingTask.cancel(true) to cancel the scheduled task from running prior to setting sequencer to null.
Other than creating Timer object every time in tick() method call use a global timer object instance and reuse it
I'm calling this tasks:
TimerTask taskA = new ThreadA(this);
TimerTask taskB = new ThreadB(this);
tasks.add(taskA);
tasks.add(taskB);
timer.schedule(taskA, 10000);
timer.schedule(taskB, 5000);
And here are the two TimerTasks:
public class ThreadA extends TimerTask {
private Ghost ghost;
public GhostThread(Ghost ghost) {
this.ghost = ghost;
}
#Override
public void run() {
ghost.stopBeingDeadAndBeAwesomeAgain();
}
}
public class ThreadB extends TimerTask {
private Ghost ghost;
public WarnThread(Ghost ghost) {
this.ghost = ghost;
}
#Override
public void run() {
ghost.beDeadAgain();
}
}
As you can see, I just call a method after 5 resp. 10 seconds. From time to time I would like to pause the "countdown". This means i want that the time until the 5 seconds are passed isn't running anymore. And then in a later point in time, I would like to resume it.
How can I achieve that??
The simplest solution would be to simply make a copy of the TimerTask, cancel it to pause, purge if you want, and then reschedule it to resume.
// pause
long timeLeft = 5000 - (new Date().getTime() - taskB.scheduledExecutionTime());
ThreadB taskBpaused = taskB.clone();
taskB.cancel();
timer.purge();
taskB = taskBpaused;
// resume
timer.schedule(taskB, timeLeft, ...);
Important note: if the task hasn't run yet, then this won't work. Google's documentation states that if it hasn't run, scheduledExecutionTime() will return an undefined value, and I don't have the capability to test what exactly that means at the moment. Needless to say, if you aren't sure it's already run, you'll need some kind of conditional to make sure the value isn't undefined.