Device.StartTimer different on WP8

OrenNovotnyOrenNovotny USMember, Insider, Beta, University ✭✭
edited September 2014 in Xamarin.Forms

Is the Device.StartTimer API supposed to be callable from a background thread to start a UI timer? It works on iOS but I get a cross-thread exception on WP8. The behavior is also different. On iOS and Android, it starts off an NSTimer or System.Threading.Timer, but on WP8 it uses a DispatcherTimer.

This puts on different behavior such that StartTimer cannot be safely called from a background thread and the resulting timer ticks on WP8 are on the UI thread and not on a threadpool thread like the others.

System.Threading.Timer is available on WP8 and should be used there instead of DispatcherTimer... maybe also on iOS to make sure the behavior matches 100%.

This needs to be unified so the behavior is the same.
Thanks

Posts

  • adamkempadamkemp USInsider, Developer Group Leader mod

    NSTimer uses the UI thread if it's created on the UI thread (though that should be set up explicitly if this API is supposed to work when called from other threads). So I think the iOS behavior should be to call the timer callback on the UI thread, and other platforms should match that.

    The behavior should definitely be consistent, but I don't agree that the timer should fire on a background thread. If you want that then use the Task Parallel Library. DeviceTimer is useful because it fires on the UI thread. Using a timer is common for UI tasks, and you shouldn't have to dispatch back to the UI thread every time the timer fires. It's more likely that people would write incorrect code if the timer fired on a background thread than if it fired on the UI thread.

    If you want the background thread then I suggest using the Task Parallel Library, which is really easy to do:

    private void DoTimerInBackground()
    {
        Task.Run(async () =>
            {
                while (_keepGoing)
                {
                    await Task.Delay(1000);
                    DoSomething();
                }
            });
    }
    
  • OrenNovotnyOrenNovotny USMember, Insider, Beta, University ✭✭
    edited September 2014

    Cool, I wasn't totally sure on the NSTimer semantics.

    There's still a big difference though -- NSTimer.Create* methods can be called from a background thread whereas the DispatcherTimer ctor can only be called from the UI thread.

    This means that a caller of StartTimer has to be already on the UI thread to invoke it.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    NSTimer.CreateScheduled methods can be called from a background thread, but they will not fire on the UI thread if you do that. When you call those methods it creates an NSTimer and then attaches it to the current run loop, which is associated with the current thread. If Xamarin intends this API to be callable from a background thread and do the right thing then they should be doing this:

    var timer = NSTimer.CreateRepeatingTimer(delay, action);
    NSRunLoop.Main.AddTimer(timer);
    

    DispatcherTimer works the same way. You can create one in a background thread as long as you give it the dispatcher it should use:

    var timer = new DispatcherTimer(delay, DispatcherPriority.Normal, action, dispatcher);
    timer.Start();
    

    Android likewise has a way to create a handler object and attach it to the main thread so that it fires there.

    I don't know whether Xamarin's implementation handles this correctly on each platform, but I think it should, and I think it should still use the UI thread.

  • OrenNovotnyOrenNovotny USMember, Insider, Beta, University ✭✭

    I agree it should be consistent, be callable from a background thread and fire on the UI thread. In that, it's currently broken.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Can you file a bug report (bugzilla.xamarin.com) and post a link here? I'll add myself as a CC and chime in if necessary.

  • OrenNovotnyOrenNovotny USMember, Insider, Beta, University ✭✭
  • ncalvetncalvet ESMember, Beta

    @OrenNovotny and @adamkemp, I also found some problems with Device.StartTimer and Android. I have added a comment to the bug.

  • dpedrinhadpedrinha DEMember ✭✭✭

    So 2 years and this is still not working as supposed.

    Any dev comment on that matter?

Sign In or Register to comment.