Can anyone tell me if this is a safe thing to do? I run a countdown timer (CountDownTimer) and when the timer reaches zero it must start again, counting down for, for example, a longer time. To do this I call
timer = new TableCount(nextTime * 1000, 100);
within the onFinish() method.
It runs without problems, but I'm concerned it may cause a memory leak. Should I rather have the timer fire some kind of notification that it is done? Here are the important bits from the activity code:
public class TableActivity extends Activity {
TableCount timer; // the count down timer
protected int nextTime;
...
// somewhere I call this - user clicked the "start" button
timer = new TableCount(nextTime * 1000, 100);
nextTime += 100; // for example
...
public class TableCount extends CountDownTimer
{
public void onFinish() {
... // check if number of iterations has been reached, else:
// start counting down from the next value
timer = new TableCount(nextTime * 1000, 100);
nextTime += 100; // for example
}
}
You will not leak memory since you are simply changing the reference of your single declaration of TableCount to a new timer which implicitly dereferences the previous object.
Even if you did something bizarre like creating a new timer each run and adding it to an array (for example) you would still not leak. You might eventually run out of memory but that's not the same as leaking since when the activity is finished(), and assuming that you are not holding a static reference somewhere else, then the memory is freed and eligible for garbage collection.
However, why not just reuse the existing timer and use schedule() to run it again?
do not need to initialize timer again....
try this...
int temp=nexttime;
public class TableCount extends CountDownTimer
{
public void onFinish() {
nexttime=temp;
timer.start();
}
}
public class ServiceCount extends CountDownTimer
{
public ServiceCount(long millisInFuture, long countDownInterval)
{
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish()
{
count = new ServiceCount((long) (1 * 60 * 1000), 1000); // 1 minute
count.start();
}
#Override
public void onTick(long millisUntilFinished)
{
Log.d("timer", "" + millisUntilFinished / 1000);
}
}
ServiceCount count = new ServiceCount((long) (1 * 60 * 1000), 1000); // 1 minute
count.start();
Related
When the delay is set to 0, what is the interval for the listener to be called?
I tried changing delay to various values, but my listener was capped at about 60 times per second, unless I changed it to larger value like 100. Is 60 fps the defualt value? How can I increase the fps?
public class test {
static long previousTime;
public static void main(String[] args) {
Timer timer = new Timer(0, new ActionListener() {
public void actionPerformed(ActionEvent e) {
long currentTime = System.currentTimeMillis();
System.out.println((currentTime - previousTime) / 1000d);
previousTime = System.currentTimeMillis();
}
});
timer.start();
while (true);
}
}
This is the code I tested with. When delay is not big enough, it prints around 0.015.
I am developing an Android app and I have a requirement to:
1) Countdown time from 'x' minutes to '1' minute and then once it is at 1 minute, count in terms of 60 sec, 30 sec and then 0.
I am counting down in terms of 1 min(60000).
My code is:
public void countdowntimer(long timeinmillis, long countdowninterval){
Log.d("hi","Iamhere 0" + timeinmillis/60000);
new CountDownTimer(timeinmillis, countdowninterval) {
public void onTick(long timeinmillis) {
//Countdown the time in terms of minutes
Log.d("hi","Iamhere 2" + timeinmillis);
tv.setText(String.valueOf((timeinmillis)/60000) + "min");
rootView.invalidate();
if(timeinmillis <= 60000 && timeinmillis > 30000){
tv.setText(String.valueOf(60) + "sec");
rootView.invalidate();
}else if(timeinmillis < 30000){
tv.setText(String.valueOf(30) + "sec");
rootView.invalidate();
}
}
public void onFinish() {
}
}.start();
}
The logs are:
Iamhere0 4
Iamhere1 3
Why is my second log showing 1 minute lesser than first log and how do I implement 60sec, 30sec countdown once it is at 1 minute?
The expected output is:
4 min
3 min
2 min
1 min -> 60sec
30sec
0
It took me some time to answer it, this was my holydays ... but here is one other solution if this is still interresting for anyone.
I prefer to use System.currentTimeInMilli to manage the timer. When I start it, I calculate the time to end then on each tick, I calculate the remaining time to show.
This design prevent the delay you will find with any incremental/decremental variable timer. To keep this class reusable, I used the Observer pattern, on each tick (100ms on this example), the Observable instance will be send to each observer.
public class RunnableTimer extends Observable implements Runnable {
private final Handler handler;
// Number of milliseconds to run before the end
private Long delay;
// Date in millis until the end of the timer
private Long countDownEnd = null;
//The calculate remaining time
private long time;
public RunnableTimer(Observer o){
this.handler = new Handler();
addObserver(o);
}
/**
* Start the timer
* #param delay : the number of milliseconds to run
*/
public void start(Long delay){
this.delay = delay;
countDownEnd = System.currentTimeMillis() + delay;
handler.postDelayed(this, 0);
}
#Override
public void run() {
time = countDownEnd - System.currentTimeMillis();
if (time > 0)
handler.postDelayed(this, 100); //Recalculate every 100ms, to keep some precision... can be more or less.
else
time = 0; //to prevent to show negative values
sendUpdate();
}
public String toString(){
long t = time / 1000;
Log.d("time", "" + t);
if(t >= 60){
return String.format("%d min.", t/60);
} if t <= 0){
return "End";
} else {
return String.format("%d sec.", (t/30+1)*30);
}
}
/**
* Send the instance to each observer.
*/
private void sendUpdate(){
setChanged();
notifyObservers(toString());
}
}
From this, you have a timer that use the system time to calculate the remaining time and the toString method that create the desire template.
To use it, simply create an instance with the Observer you want.
public class Test implements Observer {
private RunnableTimer timer;
public Test(){
timer = new RunnableTimer(this);
timer.start(65000) //65sec
}
#Override
public void update(Observable observable, Object data) {
if(data == timer){ //If the update comes from the timer
Log.d("timer", timer.toString());
}
}
}
I had to clear a huge part of my class but this should works fine since this is simpler version.
EDIT : In your case, your activity / fragment should implements Observer and in the update, where I log the timer, you should put the toString result into you textfield.
try like this :
public class MyTimeCount extends CountDownTimer {
private Button btn_code;
public MyTimeCount(long millisInFuture, long countDownInterval,Button btn) {
super(millisInFuture, countDownInterval);
btn_code=btn;
}
#Override
public void onFinish() {
btn_code.setText("Reacquire");
btn_code.setEnabled(true);
}
#Override
public void onTick(long millisUntilFinished){
btn_code.setEnabled(false);
btn_code.setText(millisUntilFinished /1000+"s");
}
}
Use AtomicInteger to maintain the threads condition.
In First Condition its display time in minute
if (min.get() > 1) {
mCount.setText(Integer.toString(min.get())+" min");
handler.postDelayed(this, 1000);
min.getAndDecrement();
}
AND
In Last one minute its goes to second condition which display time in seconds
else {
if(min.get()== 1) {
mCount.setText("60 Sec");
handler.postDelayed(this, 500);
}
else if(min.get() == 0){
mCount.setText("30 Sec");
handler.postDelayed(this, 500);
}
else
mCount.setText("0 Sec");
min.getAndDecrement();
}
Use this ...........
final TextView mCount = (TextView) findViewById(R.id.count);
final Handler handler = new Handler();
final AtomicInteger min = new AtomicInteger(4);
final Runnable counter = new Runnable() {
#Override
public void run() {
if (min.get() > 1) {
mCount.setText(Integer.toString(min.get())+" min");
handler.postDelayed(this, 1000);
min.getAndDecrement();
} else {
if(min.get()== 1) {
mCount.setText("60 Sec");
handler.postDelayed(this, 500);
}
else if(min.get() == 0){
mCount.setText("30 Sec");
handler.postDelayed(this, 500);
}
else
mCount.setText("0 Sec");
min.getAndDecrement();
}
}
};
handler.postDelayed(counter, 0);
enjoy coding.....
I've been looking for a way to create a timer that counts up in the format of mm:ss:SS and cannot for the life of me find a way of doing it. I had a timer running through a Handler and a Runnable but the timing was off and it took around 2.5 seconds to do a "second". I'll also need this timer be able to countdown too!
Can anyone give me any resources or code snippets to research on this as it is a big part of the app I'm coding.
Here's a bit of the code that I was using
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* do what you need to do */
testMethod();
/* and here comes the "trick" */
handler.postDelayed(this, 10);
}
};
public void testMethod()
{
// Log.d("Testing", "Test");
final TextView timeLabel = (TextView)findViewById(R.id.timeString);
count++;
seconds = (int)(count / 100);
final String str = ""+count;
runOnUiThread(new Runnable() {
public void run() {
timeLabel.setText("" + seconds);
// Log.d("Time", "" + count);
}
});
}
Ta!
Make small custom class by extending CountDownTimer class and then add integer or long type and then increment it, since each tick is 1 second (integer) in this case
public class TimeCounter extends CountDownTimer {
// this is my seconds up counter
int countUpTimer;
public TimeCounter(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
countUpTimer=0;
}
#Override
public void onTick(long l) {
//since each tick interval is one second
// just add 1 to this each time
myTextView.setText("Seconds:"+countUpTimer);
countUpTimer = countUpTimer+1;
}
#Override
public void onFinish() {
//reset counter to 0 if you want
countUpTimer=0;
}
}
TimeCounter timer = new TimeCounter(whenToStopInSeconds*1000, 1000);
This should get you started, in your case use long instead integer
countUpTimer = countUpTimer+1000 countUpTimer type and do time parsing as suits you
Rather than using the Handler, I'd recommend using the java.util.Timer and the java.util.TimerTask APIs. Use the Timer's void scheduleAtFixedRate() method which basically executes tasks after a fixed interval of time. The Handler's method most likely uses a fixed-delay execution.
Timer's Documentation
TimerTask's Documentation
Let's say I have the following (ref page):
public class TimerExample implements EntryPoint, ClickHandler {
public void onModuleLoad() {
Button b = new Button("Click and wait 5 seconds");
b.addClickHandler(this);
RootPanel.get().add(b);
}
public void onClick(ClickEvent event) {
// Create a new timer that calls Window.alert().
Timer t = new Timer() {
#Override
public void run() {
Window.alert("Nifty, eh?");
}
};
// Schedule the timer to run once in 5 seconds.
t.schedule(5000);
}
}
How come the Timer is still around after the method onClick exits? Shouldn't the automatic local variables be garbage collected?
Does this have to do with the fact we are talking about a HTML timer and thus the object exists outside of the automatic local variables?
The Timer.schedule(int delayMillis) method adds itself (the instance of Timer) to a List of Timers (source code from 2.5.0-rc1):
/**
* Schedules a timer to elapse in the future.
*
* #param delayMillis how long to wait before the timer elapses, in
* milliseconds
*/
public void schedule(int delayMillis) {
if (delayMillis < 0) {
throw new IllegalArgumentException("must be non-negative");
}
cancel();
isRepeating = false;
timerId = createTimeout(this, delayMillis);
timers.add(this); // <-- Adds itself to a static ArrayList<Timer> here
}
From comment by #veer explaining the scheduler thread:
The timer is going to be handled by a scheduler thread that holds a
reference to the Timer and thus righfully prevents it from being
garbage collected.
I am trying to use a time that updates a label every second (so it shows a countdown) but it only
appears to be "ticking" once and I can't work out what I'm doing wrong!
public class Puzzle extends UiApplication {
public static void main(String[] args) {
Puzzle puzzle = new Puzzle();
puzzle.enterEventDispatcher();
}
public Puzzle() {
pushScreen(new PuzzleScreen());
}
}
class PuzzleScreen extends MainScreen {
LabelField timerLabel;
Timer timer;
public static int COUNT = 0;
public PuzzleScreen() {
//set up puzzle
VerticalFieldManager vfm = new VerticalFieldManager();
add(vfm);
timerLabel = new LabelField();
timerLabel.setText("00:20");
vfm.add(timerLabel);
StartTimer();
}
void StartTimer() {
timer = new Timer();
timer.schedule(new TimerTick(), 1000);
}
private class TimerTick extends TimerTask {
public void run() {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
timerLabel.setText((COUNT++) + "");
}
});
}
}
Can anyone see what I am doing wrong..? All that happens is my label get's set to "0" and then doesn't change. I have put a breakpoint on the run in the timer tick class but I don't see it firing!
Bex
You'll need to change your Timer's schedule() call to
timer.schedule(new TimerTick(), 0, 1000);
The way you're calling it right now is saying to run it once after a second delay. This way says to run it now and every second. You probably want to use
timer.scheduleAtFixedRate(new TimerTick(), 0, 1000);
though, because it will make sure that on average your TimerTask is ran every second rather than with a normal schedule() call that says it will try waiting a second then executing, but it could fall behind if something slows it down. If scheduleAtFixedRate() is delayed, it will make multiple calls quicker than on the 1 second delay so it can "catch up." Take a look at http://www.blackberry.com/developers/docs/5.0.0api/java/util/Timer.html#scheduleAtFixedRate(java.util.TimerTask,%20long,%20long) for a more detailed explanation.