首页 > 解决方案 > 我如何在不同的应用程序状态下管理我的计时器,我正在使用 MVVM 方法?

问题描述

我有一个工作正常的计时器,我遇到的问题是当应用程序处于睡眠模式或最小化或按下后退按钮时保持计时器运行,计时器应该只在我按下停止按钮时停止我已经做好了。

/// <summary>
/// Starts the timer
/// </summary>
private void StartCommandAction()
{
    CancellationTokenSource cts = _cancellationTokenSource; // safe copy
    Device.StartTimer(TimeSpan.FromSeconds(1),() =>
    {
        if (cts.IsCancellationRequested)
        {
            return false;
        }
        else
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                var totalTimeInt = string.IsNullOrEmpty(TxtTotalTime.Value) ? 0  : int.Parse(TxtTotalTime.Value);
                var totalSec = (int)TotalSeconds.TotalSeconds;
                TimeSpan _TimeSpan = new TimeSpan(totalTimeInt, 0, totalSec); //TimeSpan.FromSeconds(TotalSeconds.TotalSeconds);
                LblTime = string.Format("{0:00}:{1:00}:{2:00}", _TimeSpan.Hours, _TimeSpan.Minutes, _TimeSpan.Seconds);
                IsVisibleTimerLabel = true;
                Count();
            });

            return true;
        }
    });

    IsVisibleButtonStart = false;
    IsVisibleButton = true;
}

标签: c#xamarin.forms

解决方案


在不知道源代码的其余部分的情况下,以下内容让我印象深刻:您期望计时器事件每秒恰好触发一次,并采用文本表示来计算总时间。这可能适用于当前的计时器实现,但不能保证。更糟糕的是,您的实现对于不同的定时器实现并不健壮。

当你总结你每次迭代的时间时,总时间的误差会越来越大。根据您的用例,这可能无关紧要,但幸运的是,对这个问题的补救措施也是对您要解决的问题的补救措施。

我的建议是:不要总结时代,而要引入固定的参考。在第一个顺序中,这可能是 a DateTime(如果精度对您来说很重要,您的解决方案看起来会有所不同,因此精度DateTime.Now会做到),但 aStopwatch也可以解决问题。

第一次启动计时器时,将当前DateTime.Now值存储在成员变量中并使用它来计算经过的时间

CancellationTokenSource cts = _cancellationTokenSource; // safe copy
this._startedAt = DateTime.Now;

Device.StartTimer(TimeSpan.FromSeconds(1),() =>
{
    if (cts.IsCancellationRequested)
    {
        return false;
    }
    else
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            TimeSpan _TimeSpan = DateTime.Now - _startedAt;
            LblTime = _TimeSpan.ToString("hh:mm:ss);
            IsVisibleTimerLabel = true;
            Count();
        });

        return true;
    }
});

请注意:要格式化,TimeSpan您可以使用ToString带有格式字符串的方法。请参阅有关如何根据需要格式化值的文档)TimeSpan.ToStringTimeSpan

这样,当返回页面时,您只需重新启动计时器(但无需设置_startedAt)。因为您已经设置_startedAt了 ,计时器将继续运行并显示正确的时间。


推荐阅读