Xamarin Forms中如何计算计时器从启动到当前的已流逝时长
计时器流逝时长最优实现方案
原有代码的问题
你当前采用定时器每秒累加1秒的实现方式会存在累计误差:设备定时器的触发间隔并非100%精准,遇到App退入后台、主线程阻塞的场景时,定时器触发会出现延迟,长期运行后计时偏差会越来越明显。
优化实现逻辑
通过「记录启动基准时间戳」的方式计算流逝时长,从根源避免累计误差:
- 启动计时器时同时记录两个值:历史累计时长、本次启动时刻的本地时间
- 每次定时器触发时,直接用当前时间减去启动时刻得到本次启动后的流逝时长,再叠加历史累计时长就是总计时长
- 该方案就算出现定时器丢触发、延迟触发的情况,下次更新时也会自动校准到正确的时间值
优化后代码
CancellationTokenSource cts = _cancellationTokenSource; // safe copy // 计时器启动逻辑 TimeSpan initialTotalTime = TimeSpan.FromMinutes(TimeSheet.TotalTime); DateTime timerStartAt = DateTime.Now; // 记录本次计时器启动的基准时间 // 1秒间隔定时器 Device.StartTimer(TimeSpan.FromSeconds(1), () => { if (cts.IsCancellationRequested) { return false; } Device.BeginInvokeOnMainThread(() => { // 直接用当前时间减启动时间计算流逝时长,无累计误差 TimeSpan elapsedSinceStart = DateTime.Now - timerStartAt; TimeSpan totalTime = initialTotalTime + elapsedSinceStart; string displaytime = totalTime.ToString(@"h\:m\:s"); TimeSheet.TotalTimeForDisplay = displaytime; Console.WriteLine("Timer"); Console.WriteLine(displaytime); }); return true; });
额外适配说明
- 支持后台运行场景,下次回到前台定时器触发时会自动计算正确的总时长,不会丢失后台的计时数据
- 如果需要实现暂停后继续计时的功能,只需要在暂停时把当前的
totalTime存为新的历史累计时长,下次启动时重新记录timerStartAt即可
内容的提问来源于stack exchange,提问作者Phuluso Ramulifho
相关产品推荐
相关产品推荐

