共计 3123 个字符,预计需要花费 8 分钟才能阅读完成。
首先说下对于 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 种形式
正文完