clean up Throttle

This commit is contained in:
Vincent Breitmoser 2017-03-27 11:43:18 +02:00
parent 910ee75798
commit b1edd02c08

View file

@ -29,50 +29,31 @@ import timber.log.Timber;
* This class used to "throttle" a flow of events. * This class used to "throttle" a flow of events.
* *
* When {@link #onEvent()} is called, it calls the callback in a certain timeout later. * When {@link #onEvent()} is called, it calls the callback in a certain timeout later.
* Initially {@link #mMinTimeout} is used as the timeout, but if it gets multiple {@link #onEvent} * Initially {@link #minTimeout} is used as the timeout, but if it gets multiple {@link #onEvent}
* calls in a certain amount of time, it extends the timeout, until it reaches {@link #mMaxTimeout}. * calls in a certain amount of time, it extends the timeout, until it reaches {@link #maxTimeout}.
* *
* This class is primarily used to throttle content changed events. * This class is primarily used to throttle content changed events.
*/ */
public class Throttle { public class Throttle {
public static final boolean DEBUG = false; // Don't submit with true private static final int TIMEOUT_EXTEND_INTERVAL = 500;
public static final int DEFAULT_MIN_TIMEOUT = 150;
public static final int DEFAULT_MAX_TIMEOUT = 2500;
/* package */ static final int TIMEOUT_EXTEND_INTERVAL = 500;
private static Timer TIMER = new Timer(); private static Timer TIMER = new Timer();
private final Clock mClock; private final Clock clock;
private final Timer mTimer; private final Timer timer;
/** Name of the instance. Only for logging. */ private final String name;
private final String mName; private final Handler handler;
private final Runnable callback;
/** Handler for UI thread. */ private final int minTimeout;
private final Handler mHandler; private final int maxTimeout;
private int currentTimeout;
/** Callback to be called */
private final Runnable mCallback;
/** Minimum (default) timeout, in milliseconds. */
private final int mMinTimeout;
/** Max timeout, in milliseconds. */
private final int mMaxTimeout;
/** Current timeout, in milliseconds. */
private int mTimeout;
/** When {@link #onEvent()} was last called. */ /** When {@link #onEvent()} was last called. */
private long mLastEventTime; private long lastEventTime;
private MyTimerTask mRunningTimerTask; private MyTimerTask runningTimerTask;
/** Constructor with default timeout */
public Throttle(String name, Runnable callback, Handler handler) {
this(name, callback, handler, DEFAULT_MIN_TIMEOUT, DEFAULT_MAX_TIMEOUT);
}
/** Constructor that takes custom timeout */ /** Constructor that takes custom timeout */
public Throttle(String name, Runnable callback, Handler handler,int minTimeout, public Throttle(String name, Runnable callback, Handler handler,int minTimeout,
@ -81,64 +62,60 @@ public class Throttle {
} }
/** Constructor for tests */ /** Constructor for tests */
/* package */ Throttle(String name, Runnable callback, Handler handler,int minTimeout, private Throttle(String name, Runnable callback, Handler handler, int minTimeout,
int maxTimeout, Clock clock, Timer timer) { int maxTimeout, Clock clock, Timer timer) {
if (maxTimeout < minTimeout) { if (maxTimeout < minTimeout) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
mName = name; this.name = name;
mCallback = callback; this.callback = callback;
mClock = clock; this.clock = clock;
mTimer = timer; this.timer = timer;
mHandler = handler; this.handler = handler;
mMinTimeout = minTimeout; this.minTimeout = minTimeout;
mMaxTimeout = maxTimeout; this.maxTimeout = maxTimeout;
mTimeout = mMinTimeout; currentTimeout = this.minTimeout;
}
private void debugLog(String message) {
Timber.d("Throttle: [%s] %s", mName, message);
} }
private boolean isCallbackScheduled() { private boolean isCallbackScheduled() {
return mRunningTimerTask != null; return runningTimerTask != null;
} }
public void cancelScheduledCallback() { public void cancelScheduledCallback() {
if (mRunningTimerTask != null) { if (runningTimerTask != null) {
if (DEBUG) debugLog("Canceling scheduled callback"); Timber.d("Throttle: [%s] %s", name, "Canceling scheduled callback");
mRunningTimerTask.cancel(); runningTimerTask.cancel();
mRunningTimerTask = null; runningTimerTask = null;
} }
} }
/* package */ void updateTimeout() { private void updateTimeout() {
final long now = mClock.getTime(); final long now = clock.getTime();
if ((now - mLastEventTime) <= TIMEOUT_EXTEND_INTERVAL) { if ((now - lastEventTime) <= TIMEOUT_EXTEND_INTERVAL) {
mTimeout *= 2; currentTimeout *= 2;
if (mTimeout >= mMaxTimeout) { if (currentTimeout >= maxTimeout) {
mTimeout = mMaxTimeout; currentTimeout = maxTimeout;
} }
if (DEBUG) debugLog("Timeout extended " + mTimeout); Timber.d("Throttle: [%s] %s", name, "Timeout extended " + currentTimeout);
} else { } else {
mTimeout = mMinTimeout; currentTimeout = minTimeout;
if (DEBUG) debugLog("Timeout reset to " + mTimeout); Timber.d("Throttle: [%s] %s", name, "Timeout reset to " + currentTimeout);
} }
mLastEventTime = now; lastEventTime = now;
} }
public void onEvent() { public void onEvent() {
if (DEBUG) debugLog("onEvent"); Timber.d("Throttle: [%s] %s", name, "onEvent");
updateTimeout(); updateTimeout();
if (isCallbackScheduled()) { if (isCallbackScheduled()) {
if (DEBUG) debugLog(" callback already scheduled"); Timber.d("Throttle: [%s] %s", name, " callback already scheduled");
} else { } else {
if (DEBUG) debugLog(" scheduling callback"); Timber.d("Throttle: [%s] %s", name, " scheduling callback");
mRunningTimerTask = new MyTimerTask(); runningTimerTask = new MyTimerTask();
mTimer.schedule(mRunningTimerTask, mTimeout); timer.schedule(runningTimerTask, currentTimeout);
} }
} }
@ -150,7 +127,7 @@ public class Throttle {
@Override @Override
public void run() { public void run() {
mHandler.post(new HandlerRunnable()); handler.post(new HandlerRunnable());
} }
@Override @Override
@ -162,20 +139,12 @@ public class Throttle {
private class HandlerRunnable implements Runnable { private class HandlerRunnable implements Runnable {
@Override @Override
public void run() { public void run() {
mRunningTimerTask = null; runningTimerTask = null;
if (!mCanceled) { // This check has to be done on the UI thread. if (!mCanceled) { // This check has to be done on the UI thread.
if (DEBUG) debugLog("Kicking callback"); Timber.d("Throttle: [%s] %s", name, "Kicking callback");
mCallback.run(); callback.run();
} }
} }
} }
} }
/* package */ int getTimeoutForTest() {
return mTimeout;
}
/* package */ long getLastEventTimeForTest() {
return mLastEventTime;
}
} }