若是使用handler.postDealyed(……, 1000)方式來進行每秒的計時,是不許確的,是的,有很大偏差,偏差的緣由在於在你收到消息,到你從新發出handler.postDealyed的時間,並非瞬間完成的,這裏面有不少邏輯處理的時間,即便沒有邏輯處理的時間,handler自己也是耗損性能的,因此消息並不可能按照理想的1000延遲來進行發送,這就致使了偏差的累積。java
時鐘接口:android
public interface IDigitalClock { /** * 開始計時 */ void start(); /** * 中止 */ void stop(); /** * 時鐘復位 */ void reset(); /** * 重啓 */ void restart(); }
正計時時鐘:git
import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.util.Log; import java.text.DecimalFormat; public class DefaultDigitalClock implements IDigitalClock { private final static String TAG = "DefaultDigitalClock"; private final static int TICK_EVENT = 0x1001; private Ticker mTicker; private Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (msg.what == TICK_EVENT) { long seconds = (long) msg.obj; String HHMMss = formatElapsedTime(seconds); clock.tick(seconds, HHMMss); } return false; } }); private long startTime; private long elapsedSeconds; private long maxSeconds; private ClockOnMainThread clock; public DefaultDigitalClock(ClockOnMainThread clock) { this(-1, clock); } public DefaultDigitalClock(long maxSeconds, ClockOnMainThread clock) { this.maxSeconds = maxSeconds; this.clock = clock; this.elapsedSeconds = -1; this.startTime = -1; } @Override public void start() { startTime = System.currentTimeMillis(); mTicker = new Ticker(); long now = SystemClock.uptimeMillis(); long next = now + (1000 - now % 1000); handler.postAtTime(mTicker, next); } @Override public void stop() { handler.removeMessages(TICK_EVENT); if (mTicker != null) { handler.removeCallbacks(mTicker); } } @Override public void reset() { elapsedSeconds = -1; startTime = -1; handler.sendMessage(newTick(0)); } @Override public void restart() { stop(); reset(); start(); } /** * 在每秒的整點執行 * {@link "https://blog.csdn.net/cpcpcp123/article/details/88542113"} */ private final class Ticker implements Runnable { public void run() { onTimeChanged(); // 在設定秒數後結束 if (maxSeconds > 0 && elapsedSeconds == maxSeconds) { stop(); return; } long now = SystemClock.uptimeMillis(); long next = now + (1000 - now % 1000); handler.postAtTime(this, next); } }; /** * 計算時間變化 */ private void onTimeChanged() { if (Thread.currentThread() != Looper.getMainLooper().getThread()) { Log.e(TAG, "onTimeChanged() must work on main thread!"); return; } elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000; Log.d(TAG, String.valueOf(elapsedSeconds)); String HHMMss = formatElapsedTime(elapsedSeconds); clock.tick(elapsedSeconds, HHMMss); } private Message newTick(long seconds) { Message msg = new Message(); msg.what = TICK_EVENT; msg.obj = seconds; return msg; } /** * @see android.text.format.DateUtils#formatElapsedTime(long) * @param elapsedSeconds 通過的秒數 */ private String formatElapsedTime(long elapsedSeconds) { // Break the elapsed seconds into hours, minutes, and seconds. long hours = 0; long minutes = 0; long seconds = 0; if (elapsedSeconds >= 3600) { hours = elapsedSeconds / 3600; elapsedSeconds -= hours * 3600; } if (elapsedSeconds >= 60) { minutes = elapsedSeconds / 60; elapsedSeconds -= minutes * 60; } seconds = elapsedSeconds; String hh = new DecimalFormat("00").format(hours); String mm = new DecimalFormat("00").format(minutes); String ss = new DecimalFormat("00").format(seconds); return String.format("%s:%s:%s", hh, mm, ss); } public interface ClockOnMainThread { void tick(long seconds, String time); } }