Leandros
Leandros

Reputation: 16825

Execute all scheduled (postDelayed) runnables in Handler

I use a Handler, which post some Runnable via postDelayed(r, DELAY_TIME), but I need to execute all Runnables before posting new via postDelayed.

Any good ideas how to achieve this as simple as possible?

Edit:

I want it basically like this:

Runnable r = new Runnable() {
    // Do some fancy action
};

if (mHandler.runnablesScheduled) {
    mHandler.flushAllScheduledRunnables();
}
mHandler.postDelayed(r, DELAY);

Upvotes: 6

Views: 2076

Answers (3)

In an Array, Keep track of runnables that are going to be called, then, if you want them to be called, cancel the postDelayed and call the runnables directly, to fire them just call the run() method from the runnable. Example code:

// Declaring the Handler and the Array that is going to track Runnables going to be tracked.
final mHandler = new Handler();  
final List<Runnable> callStack = new ArrayList<Runnable>();

// Method to remove a runnable from the track Array.
public void removePostDelayed(Runnable run) {
    callStack.remove(run);
}

// Method that we use in exchange of mHandler.postDelayed()
public void myPostDelayed(Runnable run, int delay) {
    // I remove callbacks because I don't know if can be called 2 times.
    mHandler.removeCallbacks(run);

    // We remove the Runnable from the tracking Array just in case we are going to add a Runnable that has not been called yet.
    removePostDelayed(run);

    // We add the runnable to the tracking Array and then use postDelayed()
    callStack.add(run);
    mHandler.postDelayed(run, delay);
}

// This is the Runnable. IMPORTANT: Remember to remove the Runnable from the tracking Array when the Runnable has been called.
Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        // Do some fancy stuff and remove from the tracking Array.
        removePostDelayed(this);
    }
}

// Method to execute all Runnables
public void callAllStack() {
    // We create a copy of the tracking Array because if you modify the Array while you are iterating through it, will return an Exception.
    List<Runnable> callStackCopy = new ArrayList<Runnable>();

    // here we copy the array and remove all callbacks, so they are not called by the Handler.
    for (Runnable runnable : callStack) {
        callStackCopy.add(runnable);
        mHandler.removeCallbacks(runnable);
    }

    // Then we call all the Runnables from the second Array
    for (Runnable runnable : callStackCopy) {
        runnable.run();
    }

    // And clear the tracking Array because the Handler has no more Runnables to call (This is redundant because supposedly each run() call removes himself from the tracking Array, but well... just in case we forgot something).
    callStack.clear();
}

// Example of postDelaying a Runnable while tracking if has been fired.
myPostDelayed(myRunnable, 1000)

// Example of firing all Runnables.
callAllStack();

Is pretty easy and I've commented it so you can understand it better, but if you don't understand something, just comment it. You can modify it to support multiple calls to the same Runnable or just creating your own class extension of a Handler called TrackingHandler with these functions implemented or something.

I've written the code right now on the fly so is possible that is plenty of typos, don't know.

Upvotes: 3

Delyan
Delyan

Reputation: 8911

You need a few things to make this work.

  1. Use Handler.sendMessageDelayed(Message) instead of Handler.postDelayed and assign a meaningful what value to your Message
  2. When you need to flush the queue, check whether anything is queued already with Handler.hasMessages(int). If there's anything, you can remove it with Handler.removeMessages and execute it yourself.

Upvotes: 0

kabuko
kabuko

Reputation: 36302

Well, all the Runnables are run on a queue in your handler, so if you want to run something at the end of it, the easiest way that comes to mind is to place it as another Runnable on the queue:

mHandler.post(new Runnable() {
    @Override
    public void run() {
        mHandler.postDelayed(r, DELAY);
    }
});

Upvotes: 0

Related Questions