Xamarin.Android: Why System.Timers.Timer Stops?

12/15/2018 9:52:00 AM

System.Timers.Timer

In Xamairn.Android we can use the Timer class from the .NET Framework to make a simple Timer. This timer is great. However, I encountered something strange with it in combination with Xamarin.Android that I would like to share with you. Find more about the System.Timers.Timer here.

After you create a Timer, setup the elapsed eventgive it an interval and call the start method, the Timer starts running.

    // Setup the timer
    _interval = TimeSpan.FromSeconds(1).TotalMilliseconds;
    _timer = new Timer { Interval = _interval };
    _timer.Elapsed += TimerOnElapsed;
    _timer.Start();

So far so good. We now have a Timer that runs and triggers the elapsed event after the interval is elapsed (in my example it’s set to every second). I have a full working example right here. Let's deploy it to an Android smartphone or tablet to test it. If you run it and debug it we see a trigger every second:

Running output in Android Device Monitor

(the above log is made with the Android Device Monitor)

But if we adjust the system time on our Android smartphone/tablet and set it one minute in the past, the timer will break. Notice that if you log it with the Android Device Monitor (as above) the monitoring will stop after changing the time to the past.

Huh, what just happened? 

It looks like the Timer pauses after you change the system time to the past. For example, if we set the system time to five minutes in the past, the Timer will pause and run again after those five minutes. You can easily simulate this effect with the example app. If you set the system time to one minute in the past on your Android device and then just wait for one minute till the time label shows the time again.

Let's wake up the Timer!

So, how do we wake up the Timer without having to wait for the time to have past? I couldn't find anything about it online. But after doing some tests, I found a solution by myself. It might not be the best solution, but this workaround does the job! The solution is to set the interval again, after the Timer has paused due to the change to the system time. Setting the interval will start the Timer again:

    // Setting the interval triggers the timer to start again.
    _timer.Interval = _interval;

I know what you’re thinking. Why not start the Timer by calling _timer.Start()? Or why not stop the Timer before changing the system time and start it again after the change? Well, because unfortunately, those actions don’t do the trick. 

Setting the Interval property leads to the Elapsed event to be raised once again which apparently makes the Timer run again afterwards.

You can test this solution with the example app from GitHubThis app manipulates the default generated floating button to wake up the Timer.