首先说下关于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
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?