问题
在一个项目中,使用主线程的handler.sendEmptyMessageDelayed(what, 1000),进行210秒的倒计时,最后发现误差竟然达30秒
分析
打印日志,发现每次处理计时handler消息的时间间隔大概是1.3s,足足有了0.3s的延迟,每次这样累积下来,会出现一个极大的误差。
猜测有可能是处理这条消息的逻辑时耗时了, 比如0.3s后才执行到handler.sendEmptyMessageDelayed(1000, 1000),于是改成先发送延迟消息,再处理逻辑
case 1000:
handler.sendEmptyMessageDelayed(1000, 1000);
// 处理大量逻辑...
break;
(不知道对你有没有用, 对我没卵用~)
误差的原因在于收到消息,到重新发出消息的时间,并不是瞬间完成的,这里面有很多逻辑处理的时间,即使没有逻辑处理的时间,handler本身也是耗损性能的,当UI线程处理的逻辑较多时,这个误差会来得更明显一些
解决:
使用sendEmptyMessageAtTime,在指定的时间点发出这条消息
case 1000:
long now = SystemClock.uptimeMillis();
long next = now + (1000 - now % 1000);
handler.sendEmptyMessageAtTime(0x1000, next);
// 处理大量逻辑
break;
为什么呢?假设now= 0,使用delay延迟1000ms时,因为各种损耗,假设1300毫米后才能处理这条消息,那么第一次收到消息时,时间为now = 1300,现在next = 1300 + (1000 - 1300 % 1000) = 2000,那我指定时间为2000时发这条消息,比原本提前了300ms发送补偿这个误差(原本每次延迟1000ms发送,现在相当于 (2000-1300)700ms后就发送这条消息)