android使用throttle(节流阀)技术


throttle 技术其实并不提升性能,这个技术主要是防止系统被超过自己不能处理的流量给搞垮了,这其实是个保护机制。使用throttle技术一般来说是对于一些自己无法控制的系统,只要是异步,一般都会有throttle机制。

比如:
在android系统中大量是使用ContentObserver(ContentObserver用于监听数据变化),一般情况会在ContentObserver中的onChange方法作相关查询工作,也就说会生成游标。当某时瞬间游标生成过多(数据库查询极端频繁,但属于正常的插入,而且不能用批量插入),会导致内存不够而被系统自动终止该程序。这时我们就可以使用throttle技术。
代码如下:
public class Throttle {
    public static final boolean DEBUG = false; // Don't submit with true

    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 final Clock mClock;
    private final Timer mTimer;

    /** Name of the instance.  Only for logging. */
    private final String mName;

    /** Handler for UI thread. */
    private final Handler mHandler;

    /** 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. */
    private long mLastEventTime;

    private MyTimerTask mRunningTimerTask;

    /** 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 */
    public Throttle(String name, Runnable callback, Handler handler,int minTimeout,
            int maxTimeout) {
        this(name, callback, handler, minTimeout, maxTimeout, Clock.INSTANCE, TIMER);
    }

    /** Constructor for tests */
    /* package */ Throttle(String name, Runnable callback, Handler handler,int minTimeout,
            int maxTimeout, Clock clock, Timer timer) {
        if (maxTimeout < minTimeout) {
            throw new IllegalArgumentException();
        }
        mName = name;
        mCallback = callback;
        mClock = clock;
        mTimer = timer;
        mHandler = handler;
        mMinTimeout = minTimeout;
        mMaxTimeout = maxTimeout;
        mTimeout = mMinTimeout;
    }

    private void debugLog(String message) {
        Log.d(Logging.LOG_TAG, "Throttle: [" + mName + "] " + message);
    }

    private boolean isCallbackScheduled() {
        return mRunningTimerTask != null;
    }

    public void cancelScheduledCallback() {
        if (mRunningTimerTask != null) {
            if (DEBUG) debugLog("Canceling scheduled callback");
            mRunningTimerTask.cancel();
            mRunningTimerTask = null;
        }
    }

    /* package */ void updateTimeout() {
        final long now = mClock.getTime();
        if ((now - mLastEventTime) <= TIMEOUT_EXTEND_INTERVAL) {
            mTimeout *= 2;
            if (mTimeout >= mMaxTimeout) {
                mTimeout = mMaxTimeout;
            }
            if (DEBUG) debugLog("Timeout extended " + mTimeout);
        } else {
            mTimeout = mMinTimeout;
            if (DEBUG) debugLog("Timeout reset to " + mTimeout);
        }

        mLastEventTime = now;
    }

    public void onEvent() {
        if (DEBUG) debugLog("onEvent");

        updateTimeout();

        if (isCallbackScheduled()) {
            if (DEBUG) debugLog("    callback already scheduled");
        } else {
            if (DEBUG) debugLog("    scheduling callback");
            mRunningTimerTask = new MyTimerTask();
            mTimer.schedule(mRunningTimerTask, mTimeout);
        }
    }

    /**
     * Timer task called on timeout,
     */
    private class MyTimerTask extends TimerTask {
        private boolean mCanceled;

        @Override
        public void run() {
            mHandler.post(new HandlerRunnable());
        }

        @Override
        public boolean cancel() {
            mCanceled = true;
            return super.cancel();
        }

        private class HandlerRunnable implements Runnable {
            @Override
            public void run() {
                mRunningTimerTask = null;
                if (!mCanceled) { // This check has to be done on the UI thread.
                    if (DEBUG) debugLog("Kicking callback");
                    mCallback.run();
                }
            }
        }
    }

    /* package */ int getTimeoutForTest() {
        return mTimeout;
    }

    /* package */ long getLastEventTimeForTest() {
        return mLastEventTime;
    }
}
 

你可能感兴趣的:(android,throttle)