Here's the implementation I used:
private static final long PAUSED_TIME_UNSET = 0L;
private Handler delayHandler;
private long pausedTime;
private List<Message> pendingMessages;
private Map<Message, Long> messageTimeMap;
//this should not be called while paused
protected Runnable runAfterDelay(Runnable toRun, long delayMillis) {
if (delayHandler == null) {
delayHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
pendingMessages.remove(msg);
if (msg.obj instanceof Runnable) {
((Runnable) msg.obj).run();
}
return true;
}
});
}
Message m = Message.obtain();
m.obj = toRun;
pendingMessages.add(m);
delayHandler.sendMessageDelayed(m, delayMillis);
return toRun;
}
protected void cancelDelayedRunnable(Runnable runnable) {
for (Iterator<Message> iter = pendingMessages.iterator(); iter.hasNext(); ) {
Message msg = iter.next();
if (msg.obj == runnable) {
iter.remove();
break; //assume all runnables are unique
}
}
delayHandler.removeCallbacksAndMessages(runnable);
}
protected void cancelAllDelayedRunnables() {
if (delayHandler != null) {
delayHandler.removeCallbacksAndMessages(null);
delayHandler = null;
}
pendingMessages.clear();
}
public void pause() {
if (delayHandler != null && pausedTime == PAUSED_TIME_UNSET) {
pausedTime = SystemClock.uptimeMillis();
//need to copy the Messages because their data will get cleared in removeCallbacksAndMessages
List<Message> copiedMessages = new ArrayList<Message>();
for (Message msg : pendingMessages) {
Message copy = Message.obtain();
copy.obj = msg.obj;
messageTimeMap.put(copy, msg.getWhen()); //remember the time since unable to set directly on Message
copiedMessages.add(copy);
}
//remove all messages from the handler
delayHandler.removeCallbacksAndMessages(null);
pendingMessages.clear();
pendingMessages.addAll(copiedMessages);
}
}
public void resume() {
if (delayHandler != null && pausedTime != PAUSED_TIME_UNSET) {
for (Message msg : pendingMessages) {
long msgWhen = messageTimeMap.get(msg);
long timeLeftForMessage = msgWhen - pausedTime;
delayHandler.sendMessageDelayed(msg, timeLeftForMessage);
}
messageTimeMap.clear();
pausedTime = PAUSED_TIME_UNSET;
}
}