269

I am using handler.postDelayed() to create a waiting period before the next stage of my app takes place. During the wait period I am displaying a dialog with progress bar and cancel button.

My problem is I can't find a way to cancel the postDelayed task before the time elapses.

Sufian
  • 6,405
  • 16
  • 66
  • 120
Ron
  • 2,723
  • 2
  • 15
  • 5
  • possible duplicate of [How to remove a runnable from a handler object added by postDelayed?](http://stackoverflow.com/questions/3627216/how-to-remove-a-runnable-from-a-handler-object-added-by-postdelayed) – sschuberth Jul 05 '13 at 14:15
  • Hope this gist help https://gist.github.com/imammubin/a587192982ff8db221da14d094df6fb4 MainActivity as Screen Launcher with handler & runable function, the Runnable run to login page or feed page with base preference login user with firebase. – Imam Mubin Jan 12 '19 at 09:07

5 Answers5

497

I do this to post a delayed runnable:

myHandler.postDelayed(myRunnable, SPLASH_DISPLAY_LENGTH); 

And this to remove it: myHandler.removeCallbacks(myRunnable);

James Ko
  • 32,215
  • 30
  • 128
  • 239
Varun
  • 33,833
  • 4
  • 49
  • 42
  • 76
    If you can afford to cancel all callbacks and messages on the handler and don't want to have to keep references to the runnable the third point in the accepted answer to this question is another alternative that seems to work for my case anyway: http://stackoverflow.com/questions/11299440/onbackpressed-to-kill-a-handler-within-an-activity-android (essentially calling myHandler.removeCallbacksAndMessages(null); ) – Mick Oct 26 '12 at 11:03
  • removeCallbacksAndMessages can do the trick, but personally I prefer to have the control over the scheduled runnables. Instancing and handling a pair of Runnables won't kill you app performances; otherwise, if you need more than two or three Runnables, you may need something more powerful, imho. – andrea.rinaldi Jul 13 '15 at 13:05
71

In case you do have multiple inner/anonymous runnables passed to same handler, and you want to cancel all at same event use

handler.removeCallbacksAndMessages(null);

As per documentation,

Remove any pending posts of callbacks and sent messages whose obj is token. If token is null, all callbacks and messages will be removed.

Mani
  • 2,599
  • 4
  • 30
  • 49
17

Another way is to handle the Runnable itself:

Runnable r = new Runnable {
    public void run() {
        if (booleanCancelMember != false) {
            //do what you need
        }
    }
}
Hussein El Feky
  • 6,627
  • 5
  • 44
  • 57
codeScriber
  • 4,582
  • 7
  • 38
  • 62
  • 14
    Wouldn't booleanCancelMember have to be final, which means it couldn't be changed and thus useless for this purpose? – stealthcopter Jun 26 '11 at 21:04
  • 9
    @stealthcopter no it does not have to be. – Benoit Jadinon Jul 20 '12 at 12:16
  • It does if you are making the Runnable anonymous – pablisco Jan 27 '13 at 21:55
  • You can always make a wrapper object which is final, but mutable, for your cancel check value. – Zulaxia Feb 12 '13 at 08:36
  • 7
    @pablisco It doesn't have to be final even if the Runnable is anonymous. It can be a member in the enclosing class. – Martin Apr 20 '13 at 05:36
  • Yes, it can be a member field in the enclosing class or create something like a `CancellableRunnable` class that has an option to do this in the run method. So may possibilities :) – pablisco Apr 20 '13 at 09:28
  • 6
    Not downvoting this, but be careful. With this approach, if multiple Runnables are posted delayed, you may run into nasty race conditions. This doesn't cancel the Runnable, so whether or not that code will be execute depends on the value of booleanCancelMember at the specific moment for **each** posted Runnable. Which may quickly become unpredictable. – Dennis K Dec 20 '13 at 20:45
  • 1
    If the Runnable is NOT annonymous it means I have a reference to it (`r` in this case) which means I can use `myHandler.removeCallbacks(r);`. If the Runnable is anonymous then the flag will be a member in the enclosing class, which means I need a reference to that object to change the flag, which means I again will have to have `r` anyways, which means I can do `myHandler.removeCallbacks(r);` . And if I am doing `myHandler.removeCallbacks(r);` then such flag is not necessary at all. Am I missing something? – nacho4d Jun 28 '16 at 13:52
  • this will not prevent memory leaks, removing the callback is to prefer in all cases – Gainder Dec 08 '20 at 18:57
  • @DennisK This is a Q&A forum to better understand how things work and might get nasty. For future readers to understand that this can turn into a nasty bug source, I'd say you could have downvoted it – Farid Mar 11 '21 at 14:06
1

Here is a class providing a cancel method for a delayed action

public class DelayedAction {

private Handler _handler;
private Runnable _runnable;

/**
 * Constructor
 * @param runnable The runnable
 * @param delay The delay (in milli sec) to wait before running the runnable
 */
public DelayedAction(Runnable runnable, long delay) {
    _handler = new Handler(Looper.getMainLooper());
    _runnable = runnable;
    _handler.postDelayed(_runnable, delay);
}

/**
 * Cancel a runnable
 */
public void cancel() {
    if ( _handler == null || _runnable == null ) {
        return;
    }
    _handler.removeCallbacks(_runnable);
}}
Stéphane Padovani
  • 1,157
  • 2
  • 9
  • 16
0

It worked for me when I called CancelCallBacks(this) inside the post delayed runnable by handing it via a boolean

Runnable runnable = new Runnable(){
    @Override
    public void run() {
        Log.e("HANDLER", "run: Outside Runnable");
        if (IsRecording) {
            Log.e("HANDLER", "run: Runnable");
            handler.postDelayed(this, 2000);
        }else{
            handler.removeCallbacks(this);
        }
    }
};