Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
like image 698
Leandros Avatar asked Apr 26 '13 19:04

Leandros


1 Answers

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.

like image 142
Jorge Fuentes González Avatar answered Oct 05 '22 19:10

Jorge Fuentes González