cancelling a handler.postdelayed process
Asked Answered
C

5

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.

Cochrane answered 7/12, 2010 at 15:45 Comment(2)
possible duplicate of How to remove a runnable from a handler object added by postDelayed?Samanthasamanthia
Hope this gist help 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.Afoul
M
495

I do this to post a delayed runnable:

myHandler.postDelayed(myRunnable, SPLASH_DISPLAY_LENGTH); 

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

Melbamelborn answered 7/12, 2010 at 15:52 Comment(2)
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: #11299940 (essentially calling myHandler.removeCallbacksAndMessages(null); )Fabliau
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.Lumen
C
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.

Cuman answered 30/7, 2017 at 2:18 Comment(1)
This will remove all runnable callbacks once. Otherwise, call removeCallbacks(callback) to remove specific callbackMckenney
R
17

Another way is to handle the Runnable itself:

Runnable r = new Runnable {
    public void run() {
        if (booleanCancelMember != false) {
            //do what you need
        }
    }
}
Revelationist answered 7/12, 2010 at 15:59 Comment(10)
Wouldn't booleanCancelMember have to be final, which means it couldn't be changed and thus useless for this purpose?Tyrannicide
@Tyrannicide no it does not have to be.Alkalinity
It does if you are making the Runnable anonymousLevalloisian
You can always make a wrapper object which is final, but mutable, for your cancel check value.Kolnos
@Levalloisian It doesn't have to be final even if the Runnable is anonymous. It can be a member in the enclosing class.Genniegennifer
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 :)Levalloisian
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.Michaud
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?Geotaxis
this will not prevent memory leaks, removing the callback is to prefer in all casesMyranda
@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 itFremont
F
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);
}}
Feudalize answered 18/2, 2019 at 11:45 Comment(0)
P
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);
        }
    }
};
Purnell answered 22/3, 2017 at 2:6 Comment(1)
There is no "CancelCallBacks" in your code. Maybe 'cause it doesn't exist? :)Bendigo

© 2022 - 2024 — McMap. All rights reserved.