Android 倒計時器重寫,實現可重復使用,動態修改計時時間
CountDownTimerRew 是一個可重寫、動態修改計時時間的 Android 倒計時器類。它允許開發者設置倒計時總時長、間隔時間,并通過 onTick 和 onFinish 方法實現定時回調。該類支持動態修改計時參數,如 millisInFuture 和 countDownInterval,并提供了 cancel 和 start 方法控制計時器的啟停。通過 WeakHandler 類,CountDownTimerRew 避免了內存泄漏問題。使用時,開發者只需繼承該類并實現 onTick 和 onFinish 方法即可。
CountDownTimerRew 類
public abstract class CountDownTimerRew {/*** Millis since epoch when alarm should stop.*/private long mMillisInFuture;/*** The interval in millis that the user receives callbacks*/private long mCountdownInterval;private long mStopTimeInFuture;/*** boolean representing if the timer was cancelled*/private boolean mCancelled = false;private Object mTag;/*** @param millisInFuture The number of millis in the future from the call* to {@link #start()} until the countdown is done and {@link #onFinish()}* is called.* @param countDownInterval The interval along the way to receive* {@link #onTick(long, Object)} callbacks.*/public CountDownTimerRew(long millisInFuture, long countDownInterval) {mMillisInFuture = millisInFuture;mCountdownInterval = countDownInterval;}public CountDownTimerRew setTag(Object mTag) {this.mTag = mTag;return this;}public CountDownTimerRew setMillisInFuture(long mMillisInFuture) {this.mMillisInFuture = mMillisInFuture;return this;}public CountDownTimerRew setCountdownInterval(long mCountdownInterval) {this.mCountdownInterval = mCountdownInterval;return this;}/*** Cancel the countdown.*/public synchronized final void cancel() {mCancelled = true;mHandler.removeMessages(MSG);}/*** Start the countdown.*/public synchronized final CountDownTimerRew start() {mCancelled = false;if (mMillisInFuture <= 0) {onFinish();return this;}mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;mHandler.sendMessage(mHandler.obtainMessage(MSG));return this;}/*** Callback fired on regular interval.** @param millisUntilFinished The amount of time until finished.*/public abstract void onTick(long millisUntilFinished, Object mTag);/*** Callback fired when the time is up.*/public abstract void onFinish();private static final int MSG = 1;// handles counting downprivate final Handler mHandler = new WeakHandler(Looper.getMainLooper()) {@Overridepublic void handleMessage(@NonNull Message msg) {synchronized (CountDownTimerRew.this) {if (mCancelled) {return;}final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();if (millisLeft <= 0) {onFinish();} else {long lastTickStart = SystemClock.elapsedRealtime();onTick(millisLeft, mTag);// take into account user's onTick taking time to executelong lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;long delay;if (millisLeft < mCountdownInterval) {// just delay until donedelay = millisLeft - lastTickDuration;// special case: user's onTick took more than interval to// complete, trigger onFinish without delayif (delay < 0) delay = 0;} else {delay = mCountdownInterval - lastTickDuration;// special case: user's onTick took more than interval to// complete, skip to next intervalwhile (delay < 0) delay += mCountdownInterval;}sendMessageDelayed(obtainMessage(MSG), delay);}}}};
}
WeakHandler類
public class WeakHandler extends Handler {private WeakReference<Activity> mActivity;public WeakHandler() {this(Looper.getMainLooper(), null);}public WeakHandler(@NonNull Looper looper) {this(looper, null);}public WeakHandler(@NonNull Looper looper, Activity mActivity) {super(looper);setActivity(mActivity);}public WeakReference<Activity> getActivity() {return mActivity;}public void setActivity(Activity mActivity) {this.mActivity = new WeakReference<>(mActivity);}
}
使用方法
private CountDownTimerRew mCountDownTimerRew;public CountDownTimerRew getCountDownTimerRew() {if (null == mCountDownTimerRew)mCountDownTimerRew = new CountDownTimerRew(5000, 1000) {@Overridepublic void onTick(long millisUntilFinished, Object mTag) {int iSeconds = (int) (millisUntilFinished / 1000);int iTag = mTag instanceof Integer ? (int) mTag : -1;if (iTag == 0) {//TODO}}@Overridepublic void onFinish() {}};return mCountDownTimerRew;}
//啟動計時器
getCountDownTimerRew().setMillisInFuture(180000).setMillisInFuture(500).setTag(0).start();
//取消計時器
getCountDownTimerRew().cancel();