您当前的位置: 首页 > 
  • 0浏览

    0关注

    674博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

handler实现精确计时的两种方式

沙漠一只雕得儿得儿 发布时间:2019-03-13 22:16:32 ,浏览量:0

首先说下关于handler自身的误差:

  如果使用handler.postDealyed(……, 1000)方式来进行每秒的计时,是不准确的,是的,有很大误差,误差的原因在于在你收到消息,到你重新发出handler.postDealyed的时间,并不是瞬间完成的,这里面有很多逻辑处理的时间,即使没有逻辑处理的时间,handler本身也是耗损性能的,所以消息并不可能按照理想的1000延迟来进行发送,这就导致了误差的累积。

下面我们介绍的handler精确计时的两种方式分别来自Android源码的两个控件:TextClock和CountDownTimer: 第一种方式是TextClock对于handler的时间修正:
    private final Runnable mTicker = new Runnable() {
        public void run() {
            if (mStopTicking) {
                return; // Test disabled the clock ticks
            }
            onTimeChanged();

            long now = SystemClock.uptimeMillis();
            long next = now + (1000 - now % 1000);

            getHandler().postAtTime(mTicker, next);
        }
    };

我们之前是通过postDelay来触发消息事件的,但这里系统使用了postAtTime,这样就是设置了在某一个时间点抛出handler消息,前面的

long now = SystemClock.uptimeMillis();
long next = now + (1000 - now % 1000);

精确控制了1秒的整点时间,因此系统可以在每一个整秒的时间点发出消息。

代码如下:

mCalHandler.post(mTicker);
    /**
     * 精确修正时间
     */
    private Handler mCalHandler = new Handler(Looper.getMainLooper());
    private final Runnable mTicker = new Runnable() {
        public void run() {
            long now = SystemClock.uptimeMillis();
            long next = now + (1000 - now % 1000);

            mCalHandler.postAtTime(mTicker, next);
            Log.e("buder", now + "");
        }
    };

看一下效果,基本误差都在2毫秒内

参考博客:https://www.jianshu.com/p/56f37988428b

第二种方式我们可以直接参考CountDowntimer的源码: 注意CountdownTimer本身也是不准确的,需要我们手动补偿误差时间,也是我们修改的核心点
public abstract class CountDownTimer {

    /**
     * Millis since epoch when alarm should stop.
     */
    private final long mMillisInFuture;

    /**
     * The interval in millis that the user receives callbacks
     */
    private final long mCountdownInterval;

    private long mStopTimeInFuture;
    
    /**
    * boolean representing if the timer was cancelled
    */
    private boolean mCancelled = false;

    /**
     * @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)} callbacks.
     */
    public CountDownTimer(long millisInFuture, long countDownInterval) {
        mMillisInFuture = millisInFuture;
        mCountdownInterval = countDownInterval;
    }

    /**
     * Cancel the countdown.
     */
    public synchronized final void cancel() {
        mCancelled = true;
        mHandler.removeMessages(MSG);
    }

    /**
     * Start the countdown.
     */
    public synchronized final CountDownTimer start() {
        mCancelled = false;
        if (mMillisInFuture             
关注
打赏
1657159701
查看更多评论
0.0404s