首先说下对于handler本身的误差:

如果应用handler.postDealyed(……, 1000)形式来进行每秒的计时,是不精确的,是的,有很大误差,误差的起因在于在你收到音讯,到你从新收回handler.postDealyed的工夫,并不是霎时实现的,这外面有很多逻辑解决的工夫,即便没有逻辑解决的工夫,handler自身也是耗损性能的,所以音讯并不可能依照现实的1000提早来进行发送,这就导致了误差的累积。

代码:

时钟接口:

public interface IDigitalClock {    /** * 开始计时 */ void start(); /** * 进行 */ void stop(); /** * 时钟复位 */ void reset(); /** * 重启 */ void restart();}

正计时时钟:

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);    }}

参考博客

  • handler实现准确计时的两种形式
  • Android计时罕用的7种形式