package triaina.commons.workerservice; import android.content.Intent; import android.os.Handler; import android.os.Looper; import android.os.Message; public class IntentServiceHandler extends Handler { private static final int COUNT_MASK = 0x000FFFFF; private static final int AMOUNT_TIME_MASK = 0x7FF00000; private static final int AMOUNT_TIME_SHIFT = 20; private static final int LIMIT_EXPONENTIAL = 8; private IntentServiceHandlerListener mListener; public IntentServiceHandler(Looper looper, IntentServiceHandlerListener listener) { super(looper); mListener = listener; } @Override public void handleMessage(Message msg) { int retry = getRetryCount(msg); boolean isFinished = mListener.onHandleIntent((Intent)msg.obj, retry, getAmountTime(msg)); if (!isFinished && retry < COUNT_MASK) { // backoff delay Message newMessage = new Message(); newMessage.copyFrom(msg); int next = calcNextTime(newMessage); sendMessageDelayed(newMessage, next * 1000); } else { mListener.stopSelf(msg.arg1); } } /** * exponential backoff * @param msg * @return */ private int calcNextTime(Message msg) { int amount = getAmountTime(msg); int retry = incRetryCount(msg); int n = retry < LIMIT_EXPONENTIAL ? retry : LIMIT_EXPONENTIAL; int max = (int)Math.pow(2, n); int next = (int)(Math.random() * max); setAmountTime(msg, amount + next); return next; } private int incRetryCount(Message msg) { return ++msg.arg2 & COUNT_MASK; } private int getRetryCount(Message msg) { return msg.arg2 & COUNT_MASK; } private int getAmountTime(Message msg) { return (msg.arg2 & AMOUNT_TIME_MASK) >> AMOUNT_TIME_SHIFT; } private void setAmountTime(Message msg, int t) { msg.arg2 &= ~AMOUNT_TIME_MASK; msg.arg2 |= t << AMOUNT_TIME_SHIFT; } }