Get Notified When a Background Task Completes

February 27th 2016 Universal Apps

At first sight there doesn't seem to be a way for a universal Windows application to be directly notified, when one of its background tasks has completed. Fortunately, there is an event that will get raised when a specific background task completes. In this post I'll explore how to take advantage of it and what it allows you to do.

Since there's no class representing the background task itself, the Completed event is exposed on the BackgroundTaskRegistration class that is returned by the BackgroundTaskBuilder.Register method when registering a task. Reference documentation doesn't explain the event very well, but there is also a tutorial online that does a better job at it.

In essence, you need to attach the handler to the event, when you register the task:

var builder = new BackgroundTaskBuilder();
builder.Name = "TaskName";
builder.TaskEntryPoint = "BackgroundTasks.MyTask";
var trigger = new TimeTrigger(15, false);
builder.SetTrigger(trigger);
var registration = builder.Register();
// attach the handler
registration.Completed += OnTaskCompleted;

Of course when you restart the app, you'll need to reattach the handler. You can find the BackgroundTaskRegistration instance by iterating through all registered tasks at application startup:

foreach (var task in BackgroundTaskRegistration.AllTasks)
{
    if ((task.Value.Name == "TaskName"))
    {
        task.Value.Completed += OnTaskCompleted;
    }
}

Of course you shouldn't register the task again in this case. Alternatively you can unregister the existing task and then register it anew:

task.Value.Unregister(false);

There's not all that much that you can do in the event handler. Typically you'll just want to react to the action that has been completed by the background task, e.g. read refreshed data that was written to the local storage by the background task.

If you attached the same event handler to multiple background task registrations, you can check which one triggered it to react appropriately:

void OnTaskCompleted(BackgroundTaskRegistration sender, 
    BackgroundTaskCompletedEventArgs args)
{
    var taskName = sender.Name;
}

Since the instance of BackgroundTaskRegistration is passed to the event handler as an argument, you could also detach the handler or unregister the task from inside it.

One last thing you might want to do is check whether the background task's Run method threw an exception. Achieving that is a bit unintuitive. You need to call the CheckResult() method and catch the exception it will throw, when the background task completed with an exception itself:

void OnTaskCompleted(BackgroundTaskRegistration sender, 
    BackgroundTaskCompletedEventArgs args)
{
    try
    {
        args.CheckResult();
    }
    catch (Exception e)
    {
        // react to the exception                
    }
}

Just keep in mind that this won't work when the Run method is asynchronous, because deferral.Complete() will never get called and Completed event won't be triggered at all. Since background tasks usually are asynchronous, you're better off catching the exception in the task and communicating the result back to the application another way, such as by saving data to the local storage.

A lot of credits for this blog post go to svick for bringing the Completed event to my attention.

Copyright
Creative Commons License