I want run timer for about 30000 ms and up to 8 or more times each so here is my loop but it runs all timers at once after 30000ms
public void repeatTimerTask() {
repeat = 8; // need to run 30 sec timer for 8 times but one after one
startTimer(30000); // firsat timer for 30 sec
Handler handler = new Handler();
for (int a = 1; a<=repeat; a++) {
final int finalA = a;
handler.postDelayed(new Runnable() {
#Override
public void run() {
startTimer(30000);
}
}, 30000); // delay until to finish first timer for 30 sec
}
}
To run a timer for n seconds you can use CountDownTimer
Declare two varibales globbaly. One for number of times you want to repeat. and one to keep the count of repetaion.
private int NUM_REPEAT = 4;
private int REPEAT_COUNT = 0;
Then call this method wherever you want. One thing to note if you want to run this loop 5 times you have to give number of repeation 4. Cause to satrt this function you have to call it so that will not come in count.
private void startTimer() {
new CountDownTimer(3000, 1000) {
int secondsLeft = 0;
public void onTick(long ms) {
if (Math.round((float) ms / 1000.0f) != secondsLeft) {
secondsLeft = Math.round((float) ms / 1000.0f);
// resend_timer is a textview
resend_timer.setText("remaining time is "+secondsLeft);
;
}
}
public void onFinish() {
Log.d(TAG, "timer finished "+REPEAT_COUNT);
if (REPEAT_COUNT <= NUM_REPEAT) {
startTimer();
REPEAT_COUNT++;
}
}
}.start();
}
Please try the below code, and call 'startTimer' method where you first want to start your timer :
private int startTimerCount = 1, repeat = 8;
private void startTimer(){
// if startTimerCount is less than 8 than the handle will be created
if(startTimerCount <= repeat){
// this will create a handler which invokes startTimer method after 30 seconds
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startTimer();
}
}, 30000);
// do what you want
Toast.makeText(this, "startTimer " + startTimerCount, Toast.LENGTH_SHORT).show();
}
startTimerCount++;
}
Related
I need to to show a countdown timer with 2 time periods, for example i need it to count down a 45 sec, then count down 15 sec and then loop it all over again 4 times.
I tried this code but it seems to start all the timers at ones. I want at to start the first timer and wait till it finish and then start the second timer wait till it finish and then loop it again.
what should i do??
for (int i = 0; i < labsNum; i++) {
currLabTV.setText("LAB " + (i + 1));
if(isWorking) {
timer = new WorkCounter(workNum * 1000, 1000);
timer.start();
}
if(!isWorking){
timer = new WorkCounter(restNum * 1000, 1000);
timer.start();
}
}
i extended the CountDownTimer class.
public class WorkCounter extends CountDownTimer {
public WorkCounter(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onTick(long millisUntilFinished) {
String ms = String.format("%02d:%02d" , TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished), TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished));
timeTV.setText(ms);
}
#Override
public void onFinish() {
if(isWorking) {
workoutSign.setText("REST");
}else {
workoutSign.setText("WORKOUT");
}
isWorking = !isWorking;
}
}
I created an application that can call using our SIP server. Now I want to do is to show the user how long his call has been on going. My script is actually working but I noticed that the longer the call, the laggy my app becomes. Here's the snippet of my code
Handler h = new Handler(Looper.getMainLooper());
_isOnCall = true;
long time = 0;
int x = 0;
while(_isOnCall) {
if (_isOnCall){
final int counter = 1 + x;
time += 1000;
h.postDelayed(new Runnable() {
#Override
public void run() {
(TargetDetailsActivity.this).runOnUiThread(new Runnable() {
#Override
public void run() {
final int seconds = counter % 60;
final int minutes = (counter % 3600) / 60;
final int hours = counter / 3600;
callcounter.post(new Runnable() {
#Override
public void run() {
callcounter.setText(String.format("%02d:%02d:%02d", hours, minutes, seconds));
}
});
}
});
}
}, time);
x++;
}else{
break;
}
}
Basically what the code does is just to count the seconds/minutes/hour he's been on the phone. When he hangs up, I call the code below:
_isOnCall = false;
h.removeCallbacksAndMessages(null);
I'm not sure what causes the lag. Help! Thanks.
UPDATE
I was able to make this working by utilizing galvan's suggestion using Timer. Here's my code for future reference:
private Timer myTimer;
private int counter_time=0;
public void onCallEstablished() {
myTimer = new Timer();
myTimer.schedule(new TimerTask() {
#Override
public void run() {
TimerMethod();
}
}, 0, 1000);
}
private void TimerMethod()
{
this.runOnUiThread(Timer_Tick);
}
private Runnable Timer_Tick = new Runnable() {
public void run() {
counter_time++;
int seconds = counter_time % 60;
int minutes = (counter_time % 3600) / 60;
int hours = counter_time / 3600;
callcounter.setText(String.format("%02d:%02d:%02d", hours, minutes, seconds));
}
};
public void releaseCall(){
if(myTimer != null){
myTimer.cancel();
myTimer.purge();
counter_time = 0;
}
}
It looks like every Runnable saves a reference to his parent object, a nested Runnable in this case. Try to take an heap snapshot for detecting a memory issues to see if this is the case here.
You can also make a repeat task with time interval, and stop the loop when the call ends.
Timer timer = new Timer();
TimerTask myTask = new TimerTask() {
#Override
public void run() {
// whatever you need to do every 2 seconds
}
};
timer.scheduleAtFixedRate(myTask,
firstTime,
period);
for more info about timer you can take a look at the docs
I want to change the length of my Countdowntimer when it finishs. So I got a Random Number which changes everytime.
standby_time = 15000
standby_counter = new CountDownTimer(standby_time,1000) {
#Override
public void onTick(long millisUntilFinished) {
++standby_zaehler;
}
#Override
public void onFinish() {
...
standby_zaehler = 0;
rndm_groesse = 60000;
random_zahl = r.nextInt(rndm_groesse);
standby_time = random_zahl;
standby_counter.start();
}
};
Where is my fault ? The time is not changing and takes the first value (15sec)
The countdown timers time isnt ment to be changed. You can recreate the timer to alter the time but because you are looking to start it again inside the onFinish() method it would be wise to use a different implementation better suited for this task. The java.util.Timer class does this well.
private Timer timer = new Timer();
private int standby_zaehler = 0;
private Random r = new Random();
public void scheduleNextTimer() {
// reset our countdown
standby_zaehler = 0;
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// 1 second passed, remove it to the countdown
--standby_zaehler;
// we are finished counting down. get a new max seconds
if(standby_zaehler < 0) {
standby_zaehler = r.nextInt(60);
}
}
}, 1000, 1000);
}
As you can see we dont even need to create a new timer, just reset the number and begin again.
I am using a countdown timer for audio notification... and it's not accurate from the start...
using initial parameters
private final long startCountDown;
private final long intervalCountDown;
...
startCountDown = 180 * 1000; // 3 mns - to be set from Preferences later
intervalCountDown = 60 * 1000; // 1 mns - to be set from Preferences later
...
public void onTick(long millisUntilFinished) {
Log.d(TAG, "notify countDown: " + millisUntilFinished + " msecs");
}
countDownTimer = new SwimCountDownTimer(startCountDown,intervalCountDown);
....
public void startCountDown() {
Log.d(TAG, "start countDown for " + startCountDown + " msecs" );
countDownTimer.start();
}
I can see in the log that the initial countdown is correctly set to 180000 but the next one should be 120000 and it's set to 119945 !!!
04-27 14:50:42.146: I/SWIMMER(8670): notify countDown: 180000 msecs
04-27 14:51:42.206: I/SWIMMER(8670): notify countDown: 119945 msecs
This is quite annoying as the audio notifier is expecting to say only '2 minutes" and not "1 minute and fifty nine seconds" ...; why the interval is not right ... ?
I can tricj it in setting myself the text to speech string ... but is there any way to get correct data ?
thanks for suggestions
I know it's an old question- but I've also encountered the problem, and thought I would share my solution.
Apperantly CountDownTimer isn't very accurate, so I've decided to implement a more percise countdown timer, using java.util.Timer:
public abstract class PreciseCountdown extends Timer {
private long totalTime, interval, delay;
private TimerTask task;
private long startTime = -1;
private boolean restart = false, wasCancelled = false, wasStarted = false;
public PreciseCountdown(long totalTime, long interval) {
this(totalTime, interval, 0);
}
public PreciseCountdown(long totalTime, long interval, long delay) {
super("PreciseCountdown", true);
this.delay = delay;
this.interval = interval;
this.totalTime = totalTime;
this.task = getTask(totalTime);
}
public void start() {
wasStarted = true;
this.scheduleAtFixedRate(task, delay, interval);
}
public void restart() {
if(!wasStarted) {
start();
}
else if(wasCancelled) {
wasCancelled = false;
this.task = getTask(totalTime);
start();
}
else{
this.restart = true;
}
}
public void stop() {
this.wasCancelled = true;
this.task.cancel();
}
// Call this when there's no further use for this timer
public void dispose(){
cancel();
purge();
}
private TimerTask getTask(final long totalTime) {
return new TimerTask() {
#Override
public void run() {
long timeLeft;
if (startTime < 0 || restart) {
startTime = scheduledExecutionTime();
timeLeft = totalTime;
restart = false;
} else {
timeLeft = totalTime - (scheduledExecutionTime() - startTime);
if (timeLeft <= 0) {
this.cancel();
startTime = -1;
onFinished();
return;
}
}
onTick(timeLeft);
}
};
}
public abstract void onTick(long timeLeft);
public abstract void onFinished();
}
Usage example would be:
this.countDown = new PreciseCountdown(totalTime, interval, delay) {
#Override
public void onTick(long timeLeft) {
// update..
// note that this runs on a different thread, so to update any GUI components you need to use Activity.runOnUiThread()
}
#Override
public void onFinished() {
onTick(0); // when the timer finishes onTick isn't called
// count down is finished
}
};
to start the countdown, simply call countDown.start().
countDown.stop() stops the countDown, which could be restarted using countDown.restart().
Hope this is any help for anyone in the future.
This is an extension on what Noam Gal posted. I added extra functionality where you can pause and resume the timer. This was very helpful in my case.
public abstract class PreciseCountdownTimer extends Timer {
private long totalTime, interval, delay;
private TimerTask task;
private long startTime = -1;
private long timeLeft;
private boolean restart = false;
private boolean wasCancelled = false;
private boolean wasStarted = false;
public PreciseCountdownTimer(long totalTime, long interval) {
this(totalTime, interval, 0);
}
public PreciseCountdownTimer(long totalTime, long interval, long delay ) {
super("PreciseCountdownTimer", true);
this.delay = delay;
this.interval = interval;
this.totalTime = totalTime;
this.task = buildTask(totalTime);
}
private TimerTask buildTask(final long totalTime) {
return new TimerTask() {
#Override
public void run() {
if (startTime < 0 || restart) {
startTime = scheduledExecutionTime();
timeLeft = totalTime;
restart = false;
} else {
timeLeft = totalTime - (scheduledExecutionTime() - startTime);
if (timeLeft <= 0) {
this.cancel();
wasCancelled = true;
startTime = -1;
onFinished();
return;
}
}
onTick(timeLeft);
}
};
}
public void start() {
wasStarted = true;
this.scheduleAtFixedRate(task, delay, interval);
}
public void stop() {
this.wasCancelled = true;
this.task.cancel();
}
public void restart() {
if (!wasStarted) {
start();
} else if (wasCancelled) {
wasCancelled = false;
this.task = buildTask(totalTime);
start();
} else {
this.restart = true;
}
}
public void pause(){
wasCancelled = true;
this.task.cancel();
onPaused();
}
public void resume(){
wasCancelled = false;
this.task = buildTask(timeLeft);
this.startTime = - 1;
start();
onResumed();
}
// Call this when there's no further use for this timer
public void dispose() {
this.cancel();
this.purge();
}
public abstract void onTick(long timeLeft);
public abstract void onFinished();
public abstract void onPaused();
public abstract void onResumed();
}
Usage example would be almost exactly the same:
this.timer = new PreciseCountdownTimer(totalTime, interval, delay) {
#Override
public void onTick(long timeLeft) {
// note that this runs on a different thread, so to update any GUI components you need to use Activity.runOnUiThread()
}
#Override
public void onFinished() {
onTick(0); // when the timer finishes onTick isn't called
// count down is finished
}
#Override
public void onPaused() {
// runs after the timer has been paused
}
#Override
public void onResumed() {
// runs after the timer has been resumed
}
};
Enjoy and have fun :D
That's true and I observed the same behaviour (logging millisUntilFinished):
9999 // 1 ms lag
8997 // 3 ms lag
7995 // 5 ms lag
6993 // 7 ms lag
5991 // 9 ms lag
4987 // 13 ms lag
3985 // 15 ms lag
2979 // 21 ms lag
1975 // 25 ms lag
971 // 29 ms lag
The reason is that it's implementation doesn't take into account the time a message stays in thread's message queue and the time needed for synchronization.
I prepared the fixed version (repo, class source).
It prints the following sequence:
9999 // 1 ms lag
8999 // 1 ms lag
7999 // 1 ms lag
6997 // 3 ms lag
5997 // 3 ms lag
4998 // 2 ms lag
3997 // 3 ms lag
2998 // 2 ms lag
1997 // 3 ms lag
997 // 3 ms lag
Small lag is still here, but the most important thing is that it doesn't accumulate.
To install it add in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Add the dependency:
dependencies {
implementation 'com.github.cardinalby:accurate-count-down-timer:1.0'
}
Instead of using millisUntilFinished, you can use a variable to hold the remaining time and in every onTick, minus the variable with the interval. In this way, remainingTime is always accurate.
private class MyTimer(
countDownTime: Long,
interval: Long
) : CountDownTimer(countDownTime, interval) {
private var remainingTime = countDownTime
override fun onFinish() {
}
override fun onTick(millisUntilFinished: Long) {
// consume remainingTime here and then minus interval
remainingTime -= interval
}
}
I have a fairly simple JavaFX GUI application which has an label that shows how much time is left until a certain action starts. To achieve this, I've created a DownloadTimer class as shown below:
public class DownloadTimer(){
private int minutes;
private int seconds;
private Timer innerTimer = new Timer();
private TimerTask innerTask;
private boolean isActive;
public DownloadTimer(int minutes, int seconds) {
if (seconds > 60) {
int minToAdd = seconds / 60;
this.minutes = minutes;
this.minutes += minToAdd;
this.seconds = seconds % 60;
} else {
this.minutes = minutes;
this.seconds = seconds;
}
}
public void start() {
innerTask = new TimerTask() {
#Override
public void run() {
isActive = true;
System.out.println(getTime());
if (seconds == 0 && minutes > 0){
minutes -= 1;
seconds = 59;
} else if (seconds == 0 && minutes == 0){
isActive = false;
innerTimer.cancel();
innerTimer.purge();
System.out.println("DownloadTimer DONE");
} else {
seconds -= 1;
}
}
};
innerTimer.scheduleAtFixedRate(innerTask, 0, 1000);
}
}
And then, I'm creating the DownloadTimer object and starting the countdown from my Main (JavaFX) class:
/*
code omitted for better readability
*/
downloadTimer = new DownloadTimer(0, 5);
// label gets the .getTime() value, which returns a formatted String like "00:05", "00:04", etc.
lblTimer.setText( downloadTimer.getTime() );
// start the countdown
downloadTimer.start();
// create a new timer which checks if the downloadTimer is still counting
final Timer timer = new Timer();
TimerTask timerTask = new TimerTask(){
#Override
public void run(){
if (downloadTimer.getIsActive() == false){
timer.cancel();
timer.purge();
System.out.println("GUI timer DONE");
} else {
// if it's still running, then continuously update the label's text
lblTimer.setText( downloadTimer.getTime() );
// this is where I get the error described below
}
}
};
// repeat after 1000ms
timer.scheduleAtFixedRate(timerTask, 0, 1000);
The problem I'm encountering with this is that I can't set the label text with lblTimer.setText( downloadTimer.getTime() ); from the Main class, and the error I'm getting is TimerThread.run() line: not available [local variables unavailable] as seen here.
I've read about ScheduledThreadPoolExecutor and Java Timer vs ExecutorService, but I'm curious if this can be done using two separate Timers and TimerTasks. Any help and/or tips would be greatly appreciated.
I'm surprised you're not seeing an exception. To update a label from a separate thread, one needs to schedule an update to be run in the FX thread:
Platform.runLater(new Runnable() {
public void run() {
lblTimer.setText(downloadTimer.getTime());
}
});