CountDownTimer.cancel() is not working in the below code:
myTimer = new CountDownTimer(10000, 1000) {
public void onFinish() {
}
#Override
public void onTick(long millisUntilFinished) {
if(null != myObject){
myTimer.cancel();
}
}
}.start();
In the above code I have started a CountDownTimer which check if the object is not null and cancels the Timer accordingly. The object is set by some listener at any point of time.
Please refer and suggest. Am I doing the right thing here?
Solution By Gautier Hayoun :
Just made a drop-in replacement for
CountDownTimer that you can cancel
from within onTick : Github link–
Gautier Hayoun Dec 12 '10 at 1:04
Solution By Gautier Hayoun :
Just made a drop-in replacement for CountDownTimer that you can cancel from within onTick : Github link– Gautier Hayoun Dec 12 '10 at 1:04
Instead of CountDownTimer use TimerTask
final static long INTERVAL=1000;
final static long TIMEOUT=10000;
TimerTask task=new TimerTask(){
#Override
public void run() {
elapsed+=INTERVAL;
if(elapsed>=TIMEOUT){
this.cancel();
displayText("finished");
return;
}
//if(some other conditions)
// this.cancel();
displayText("seconds elapsed: " + elapsed / 1000);
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, INTERVAL, INTERVAL);
private void displayText(final String text){
this.runOnUiThread(new Runnable(){
#Override
public void run() {
mTextField.setText(text);
}
});
}
Related
I made a simple timer class using RxJava Observables:
public abstract class CountDownTimer {
private final TimeUnit timeUnit;
private final Long startValue;
private Disposable disposable;
public CountDownTimer(Long startValue, TimeUnit timeUnit) {
this.timeUnit = timeUnit;
this.startValue = startValue;
}
public abstract void onTick(long tickValue);
public abstract void onFinish();
public void start(){
Observable.zip(
Observable.range(0, startValue.intValue()),
Observable.interval(1, timeUnit),
(integer, aLong) -> startValue - integer)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Long>() {
#Override
public void onSubscribe(Disposable d) {
disposable = d;
}
#Override
public void onNext(Long aLong) {
onTick(aLong);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
onFinish();
}
});
}
public void cancel(){
if(disposable!=null) {
disposable.dispose();
}
}
}
I use this class to set progress on a ProgressBar (initiation from a method in Fragment):
timer = new CountDownTimer(QUESTION_TIME, TimeUnit.SECONDS) {
#Override
public void onTick(long tickValue) {
//set progress color
}
#Override
public void onFinish() {
//set progress color
}
};
timer.start();
When onFinish() tick from timer, onDestroyView from fragment, and other places in my fragment code, I call this:
if(timer != null){
timer.cancel();
}
And I can see from logging that cancel() is called and it is disposed of. However, even when resetting timer (I have a class variable Countdowntimer timer) like I showns in my second code example, I can see that the old timer is still active and updates the progressbar (both the old, and new timer updates the progressbar, so progress jumps between these 2 values).
I don't understand this, why is the timer not completly disposed of? Why does the "old timer" still continue to update the values?
EDIT:
This is how the timer class behaves in a fragment:
TICK 25 //first call to create new timer
TICK 24
TICK 23
TICK 22
TICK 21
TIMER CANCELLED //first call stopped. timer.cancel() called (which then calls disposable.dispose() in CountDownTimer.class)
TICK 25 //second call
TICK 25 // somehow the first call also start again?
TICK 24
TICK 24
TICK 23
TICK 23
TICK 22
TICK 22
TIMER CANCELLED //cancel second call
TICK 21 //first or second call still continues
TICK 20
TICK 19
TICK 18
And it will continue to "stack on" more timers (which I called dispose() on)...
I'm not sure why you do this in this way, but there is an operator intervalRange that gets you this in fewer steps. Also managing the disposable could be a problem if you are reusing the same Countdowntimer. Try this:
class CountdownTimer {
SerialDisposable disposable = new SerialDisposable();
//...
public void start() {
disposable.set(
Observable.intervalRange(0, startValue,
1, timeUnit, AndroidSchedulers.mainThread())
.subscribe(
tick -> onTick(startValue - tick)
error -> error.printStackTrace()
() -> onFinish()
)
);
}
public void cancel() {
disposable.set(null);
}
}
Try to clear the instance through GC too. add the following to all the places where you are calling timer.cancel(). Setting it to null will notify the GC that the timer instance is ready to be cleared.
if(timer != null) {
timer.cancel();
timer= null;
}
I have implemented a simple timer with CountDownTimer on my game and I need it to start ater a few seconds when the activity is started.
On my main activity's onCreate method, I call this:
playingTime();
Which is as follow
public void playingTime() {
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
String elapsedTime = String.valueOf(millisUntilFinished / 1000);
timer.setText(elapsedTime);
}
public void onFinish() {
timer.setText(R.string.timer_game_over_text);
}
}.start();
}
The timer start normally but immediatelly as the activity is launched. I would like to set a delay before it get executed or if there is a better way to set timer in games. (Count down timer and nomal timer)
You can use the handler in onCreate() method as shown below and playingTime will be called after 1 second
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
playingTime();
}
}, 1000);
You can add delay using Handler like as below:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Executed after YOUR_DELAY_IN_MILLIS
playingTime()
}
}, YOUR_DELAY_IN_MILLIS);
Put the code in your activity onCreate() method
You can set a delay like this :
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
// call method here
}
}, MY_DELAY_IN_MS);
Replace MY_DELAY_IN_MS with your own delay
I'm trying to make a countdown timer in android for use in a small android app. The app will countdown from some number of seconds to 0, upon which it will do some action. I'm using the coundowntimer supplied by android.os.countdowntimer. Here is my code:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.quizlayout);
new CountDownTimer(30000, 1000) {
TextView tx = (TextView) findViewById(R.id.textView2);
public void onTick(long millisUntilFinished) {
tx.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
tx.setText("done!");
}
}.start();
}
However, this countdown timer is really slow. It takes like 3 real-time seconds for the timer to countdown by one second. I wonder what's going on? The code I have above is more or less copied straight from google (CountDownTimer)
Can anyone help me as per why my timer is so slow, and offer a way to speed it up a bit?
(EDIT): I am running this on an emulator, the intel atom x86. I am emulating an android 2.3.3 environment.
According to Android documentation for countdown timer
The calls to onTick(long) are synchronized to this object so that one call to onTick(long) won't ever occur before the previous callback is complete. This is only relevant when the implementation of onTick(long) takes an amount of time to execute that is significant compared to the countdown interval.
Take a look at this example for countdown timer
Countdown timer example
Alternately you can spawn a new thread and just get that thread to sleep for the interval you want and take actions when it wakes or vice versa.
You can also timertask
use a handler that will post the same runnable . this will remove the need for extra threads :
Handler handler=new Handler();
handler.postRunnable(... , 1000) ;
in the runnable , call the postRunnable again for the same handler (and add a condition for when to stop) .
CountDownTimer is not efficient regardless to ui updating performances. For a flawless ui update, it is better to create a custom countdown. I did my own so here it is. It is flawless on my app.
public abstract class CountDown {
int totalTime = 0;
int tickTime = 0;
Thread thread;
boolean canceled = false;
public CountDown(int totalTime,int tickTime){
this.totalTime = totalTime;
this.tickTime = tickTime;
}
public abstract void onTick();
public abstract void onFinish();
public void start(){
thread = new Thread(new Runnable() {
#Override
public void run() {
// Do in thread
canceled = false;
for (int elapsedTime = 0; elapsedTime < totalTime; elapsedTime += tickTime) {
if(!canceled){
onTick();
try {
thread.sleep(tickTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
break;
}
}
if(!canceled){
onFinish();
}
}
});
thread.start();
}
public void cancel(){
canceled = true;
}
}
Remember that every time you have to update your ui, call a runOnUiThread, or else you will have an exception, you are not in a handler and not on ui thread.
Here is how to use it in your code, it is identical to CountDownTimer, so you could just rename lines in your code :
CountDown cDown = new CountDown(10000, 20) {
public void onTick() {
// Do something
}
public void onFinish() {
runOnUiThread(new Runnable() {
#Override
public void run() {
myButton.setImageDrawable(drawable);
}
});
}
};
Im using a Timer to continuously update a TextView, but I'm having trouble restarting the timer during the onResume() method. I use timer.cancel() in the onPause() and onDestroy() methods, but how do I restart the timer in onResume()?
This is my timer code...
int delay = 1000;
int period = 1000;
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
//I update the TextView here
}
}, delay, period);
An easier alternative is to use the Handler class. I wouldn't recommend the Timer class because it has no bearing on the life cycle of your Activity and you will have to worry about any potential threading problems yourself. The beauty of using the Handler is that all your callbacks will be on the main thread (so no threading issues to worry about). The following is a simple example on how to do this.
#Override
protected void onCreate(Bundle savedInstanceState)
{
....
mHandler = new Handler();
}
#Override
protected void onResume()
{
mHandler.postDelayed(myRunnable, UPDATE_RATE);
}
#Override
protected void onPause()
{
mHandler.removeCallbacks(myRunnable);
}
private final Runnable myRunnable= new Runnable() {
#Override
public void run()
{
//Do task
mHandler.postDelayed(myRunnable, UPDATE_RATE);
}
}
You dont restart the timer. Instead use a new timer i.e inside onResume() create a new timer. As you are no longer using the previous one, garbage collection will take care of it. So in onResume() use the following code:
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
//update the TextView here
}
}, delay, period);
I am working on a layout which shows a tab like structure on bottom of the layout. Which I need to show on double tap and then hide it after 5 sec. So I am using this countdown timer:
public void timer()
{
cdt=new CountDownTimer(5000,1000) {
#Override
public void onTick(long millisUntilFinished) {
System.out.println("Timer Working"+millisUntilFinished+"");
}
#Override
public void onFinish() {
System.out.println("Finished");
main =(LinearLayout)findViewById(R.id.parent);
ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)main.getLayoutParams();
mlp.height=420;
set_up_views();
find_module();
tl.setVisibility(View.INVISIBLE);
}
}.start();
}
But I dont know how to stop and restart this timer. How can I do?
I suggest you not to Use CountDownTimer for this case.
Use Handler.postDelayed(Runnable runnable, long delay)
public class yourActivity extends Activity
{
public Handler handler = new Handler();
...
public void hideAfter5Sec()
{
handler.postDelayed(new Runnable()
{
View view = findViewById(view_to_hide);
view.setVisibility(View.INVISIBLE);
}, 5000);
}
}
postDelayed will execute that code after 5Sec.
EDITED:
postDelayed will be call only once after 5 Sec through Lopper.loop(). If there are multiple call to hideAfter5Sec() then only you will get multiple call to postDelayed.
If you have multiple call hideAfter5Sec() i dont think there is any wrong because hideAfter5Sec() is just hidding it. so if it one or many your view will be hidden.
If in case you want to hide only in the last call of hideAfter5Sec() use this variant.
public class yourActivity extends Activity
{
public Handler handler = new Handler();
public long lastHideAfter5Sec = 0L;
...
public void hideAfter5Sec()
{
lastHideAfter5Sec = System.currentTimeMillis();
handler.postDelayed(new Runnable()
{
if(System.currentTimeMillis() - lastHideAfter5Sec < 5000)
return;
View view = findViewById(view_to_hide);
view.setVisibility(View.INVISIBLE);
}, 5000);
}