Android Handler计时的优化
handler计时方式,我们通常是在主线程中通过handler.postDealyed(……,200),并在onHandleMessage中继续post消息,这样就实现了每隔200ms进行一次消息循环。
这种方式是不准确的,有误差,误差的原因在于在你收到消息,到你重新发出handler.postDealyed的时间,并不是瞬间完成的,这里面有很多逻辑处理的时间,即使没有逻辑处理的时间,handler本身也是耗损性能的,所以消息并不可能按照理想的200ms延迟来进行发送。
所以,我们每次在post的时候,都需要对计时进行下补偿,查看TextClock源码,它是这样处理的:
private final Runnable mTicker = new Runnable() { public void run() { onTimeChanged(); long now = SystemClock.uptimeMillis(); long next = now + (1000 - now % 1000); getHandler().postAtTime(mTicker, next); } };
这里系统使用了postAtTime,这是为什么呢?再看前面两行代码,代个值进去试下,假如now取出来是1200,那么next =1200 + (1000 - 1200 % 1000)也就是next=2000。虽然我们前一次本该在1000触发的事件,被各种逻辑延迟到1200,那么如果用postDelay,这个延迟就被累积了,但如果用这种方式,误差就被补偿了。
因此,我们可以这样用:
private void startTimeHandler() { //误差补偿算法,如now取出来是1200,那么next = 1200 + (1000 - 1200 % 1000)也就是next= 2000。 long now = SystemClock.uptimeMillis(); // long next = now + (1000 - now % 1000); mTimeHander.sendEmptyMessageAtTime(0, next); }
private static class TimeHander extends Handler { WeakReference<RecordService> rsWeakReference; TimeHander(RecordService rs) { this.rsWeakReference = new WeakReference(rs); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); RecordService rs = rsWeakReference.get(); rs.startTimeHandler(); } }
说明:
SystemClock.uptimeMillis() // 从开机到现在的毫秒数(手机睡眠的时间不包括在内); System.currentTimeMillis() // 从1970年1月1日 UTC到现在的毫秒数;
System.currentTimeMillis() 获取的时间,是可以通过System.setCurrentTimeMillis修改的,那么,在某些情况下,一但被修改,时间间隔就不准了。
参考链接:https://www.jianshu.com/p/56f37988428b