如何从 Device.StartTimer 取消计时?

17

当我使用System.Threading.Timer时,我可以停止我的计时器并重新启动它:

protected override void OnScrollChanged(int l, int t, int oldl, int oldt)
{
    if (timer == null)
    {
        System.Threading.TimerCallback tcb = OnScrollFinished;
        timer = new System.Threading.Timer(tcb, null, 700, System.Threading.Timeout.Infinite);
    }
    else
    {
        timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
        timer.Change(700, System.Threading.Timeout.Infinite);
    }
}
什么是停止Device.StartTimer并重新启动它的最佳方法?

你可以使用Thread.Sleep,也可以在构造函数中设置周期参数。 - Adrian Stanculescu
不,我不能睡觉。应用程序必须正常工作。 - Kirill
1个回答

23
我猜您指的是XamarinForms中的Device.StartTime。停止或继续重复任务的方式取决于第二个参数的返回值。
// run task in 2 minutes
Device.StartTimer(TimeSpan.FromMinutes(2), () =>
{
    if (needsToRecur)
    {
        // returning true will fire task again in 2 minutes.
        return true;
    }

    // No longer need to recur. Stops firing task
    return false; 
});
如果您想暂时停止这个计时器,并在一段时间后再次启动它,那么您需要再次调用Device.StartTimer。最好将其封装到自己的类中,在其中使用一个私有成员来确定连续任务是否仍在运行。例如:
public class DeviceTimer
{
  readonly Action _Task;
  readonly List<TaskWrapper> _Tasks = new List<TaskWrapper>();
  readonly TimeSpan _Interval;
  public bool IsRecurring { get; }
  public bool IsRunning => _Tasks.Any(t => t.IsRunning);

  public DeviceTimer(Action task, TimeSpan interval, 
    bool isRecurring = false, bool start = false)
  {
    _Task = task;
    _interval = interval;
    IsRecurring = isRecurring;
    if (start)
      Start();
  }

  public void Restart()
  {
    Stop();
    Start();
  }

  public void Start()
  {
    if (IsRunning)
      // Already Running
      return;

    var wrapper = new TaskWrapper(_Task, IsRecurring, true);
    _Tasks.Add(wrapper);

    Device.StartTimer(_interval, wrapper.RunTask);
  }

  public void Stop()
  {
    foreach (var task in _Tasks)
      task.IsRunning = false;
    _Tasks.Clear();
  }


  class TaskWrapper
  {
    public bool IsRunning { get; set; }
    bool _IsRecurring;
    Action _Task;
    public TaskWrapper(Action task, bool isRecurring, bool isRunning)
    {
      _Task = task;
      _IsRecurring = isRecurring;
      IsRunning = isRunning;
    }

    public bool RunTask()
    {
      if (IsRunning)
      {
        _Task();
        if (_IsRecurring)
          return true;
      }

      // No longer need to recur. Stop
      return IsRunning = false;
    }
  }         
}

我面临的问题是,即使用户导航到另一个页面,计时器仍然在继续运行。您的解决方案看起来很有前途,但我的问题是当用户从页面导航时,应该由哪个操作/事件调用Stop()函数?如果我使用OnDisappearing操作,它也会在屏幕锁定或应用程序转到后台时触发。我也不能使用返回按钮按下事件,因为如果按下软件返回按钮,则在androd上不会触发该事件。你怎么看? - Emil
1
我已经用我的实验结果更新了你的代码。如果你有任何异议,请随时撤销修改。 - Shimmy Weitzhandler
为什么要使用任务列表 List<TaskWrapper> _Tasks?这个也可以只用一个吗? - testing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,