Timer.Elapsed处理程序突然停止

时间:2018-02-09 21:05:54

标签: c# xamarin timer xamarin.android

var checkTimer = new Timer();
checkTimer.Elapsed += (s, e) =>
{
    bool? doneIndexing = serviceConnection.GetIndexStatus();                    
    Log.Debug(TAG, $"Indexing status: {doneIndexing}");
    if (doneIndexing.HasValue && doneIndexing == true)
    {
        Log.Debug(TAG, "Done indexing, updating UI");
        var indexStatusView = FindViewById<TextView>(Resource.Id.indexStatusView);
        var indexProgress = FindViewById<ProgressBar>(Resource.Id.indexProgress);
        indexStatusView.Text = GetString(Resource.String.done_indexing);
        indexProgress.Visibility = ViewStates.Gone;
        checkTimer.Enabled = false;
    }
};
checkTimer.Interval = 100;
checkTimer.Enabled = true;

执行在indexStatusView.Text = GetString(Resource.String.done_indexing)处停止。当doneIndexing == true时,它会被调用几次,但即使我将禁用行移到顶部,执行仍然会在同一行停止。什么可能导致这种情况?

2 个答案:

答案 0 :(得分:4)

  

执行在indexStatusView.Text停止.....

在UI线程上执行UI更新,即:

if (doneIndexing.HasValue && doneIndexing == true)
{
    var indexStatusView = FindViewById<TextView>(Resource.Id.indexStatusView);
    var indexProgress = FindViewById<ProgressBar>(Resource.Id.indexProgress);
    Log.Debug(TAG, "Done indexing, updating UI");
    RunOnUiThread(() =>
    {
        indexStatusView.Text = GetString(Resource.String.done_indexing);
        indexProgress.Visibility = ViewStates.Gone;
    });
    checkTimer.Enabled = false;
}

答案 1 :(得分:-4)

我只是查看了这个计时器,我最好的猜测是你有一个被swallwoed的异常。显然这个Timer使用了大量的多线程。甚至可以在不同的池线程上以parlell运行多个Elapsed Events。

Unfortuantley多线程非常擅长吞咽异常。而这个似乎没有任何能力来避免这种情况或暴露例外:https://developer.xamarin.com/api/event/System.Timers.Timer.Elapsed/

“如果Timer.SynchronizingObject属性为null,则在ThreadPool线程上引发Timer.Elapsed事件。如果Timer.Elapsed事件的处理持续时间超过Timer.Interval,则可能在另一个ThreadPool上再次引发该事件在这种情况下,事件处理程序应该是可重入的。“

“Timer组件捕获并抑制Timer.Elapsed事件的事件处理程序抛出的所有异常。在.NET Framework的未来版本中,此行为可能会发生变化。”

你调试它的能力取决于你从异常线程中获取异常的技巧以及可能的一般多线程。考虑到这项工作可能具有长期运行性质,也许速率限制会更好?在另一个线程中运行这样的代码:

integer interval = 20;
DateTime dueTime = DateTime.Now.AddMillisconds(interval);

while(true){
  if(DateTime.Now >= dueTime){
    //insert code here

    //Update next dueTime
    dueTime = DateTime.Now.AddMillisconds(interval);
  }
  else{
    //Just yield to not tax out the CPU
    Thread.Sleep(1);
  }
}