31 Days of Windows 8 | Day #12: Background Tasks

This article is Day #12 in a series called 31 Days of Windows 8.  Each of the articles in this series will be published for both HTML5/JS and XAML/C#. You can find additional resources, downloads, and source code on our website.

advertisementsample

Today, we are talking about Background Tasks.  The short way to describe Background Tasks is this:

A Background Task is the code that runs when your app doesn’t.

Think of the scenarios:

  • Continue streaming audio, even when the user is running another app.
  • Update the user’s Live Tile to reflect new data.
  • Pop a Toast Notification to let the user know something important has happened.
  • Update the user’s lock screen, even when the device is locked.

Getting a Background Task established and registered with the system is a two-step process.  First, you have to register the Background Task in your package.appxmanifest file.  Once that has been done, you still need to register the events of that Task with the system from your application code, and then there are additional events to manage what happens when Background Tasks finish.  We will cover these scenarios in this article.

Creating a Background Task Class

My first step is always to create a secondary project that will contain my Background Tasks.  This isn’t required, but it’s a nice visual separation of your code.

12-XAML-AddProject

When you create a new Project, choose “Windows Runtime Component” as the project type.

12-XAML-WindowsRuntimeComponent   By default, you are given a class named Class1.cs.  You can either rename it, or just delete it and add a new Class to the new project.  In either case, you’re going to create a Class file named TileUpdater.cs.

Now, Background Tasks must implement a very specific interface: IBackgroundTask.  It only implements one method, Run(), and this is the method that will be called when our app kicks off the Background Task.  Just to get you started, here’s what my C# looks like after implementing the interface:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Background;

namespace BackgroundTasks
{
    public sealed class TileUpdater : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            //We will add code here later.
        }
    }
}

 

I’ve added a comment where our code will reside, but for now, this is a good start.

Setting Up Your Package.Appxmanifest File

The next step in this process is to declare that we will be using Background Tasks in this application.  We do this in the package.appxmanifest file, in the Declarations section, as illustrated by the screenshot below (click to enlarge):

12-XAML-Appxmanifest

As you can see, we’ve added a declaration for Background Tasks (you will a new one of these for each Background Task you want to add to your project), and set the entry point to be BackgroundTasks.TileUpdater, our new class file.  Next, we need to register this task in our actual application, so that Windows 8 knows to run it at the appropriate times.

Registering Your Background Task

We’re going to take a couple of steps in this code of our MainPage.xaml.cs file, starting with checking to see if our Background Task has already been registered to the system.  I generally do this as soon as the page loads, in my OnNavigatedTo method.  I’ve create a new CheckTaskRegistration() method that checks this status for me, and sets a global Boolean value in the page.  You could certainly do this in your App.xaml.cs file as well, but for our simple purposes, this location works fine.

bool isTaskRegistered = false;

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    CheckTaskRegistration();
}

private void CheckTaskRegistration()
{
    foreach (var task in BackgroundTaskRegistration.AllTasks)
    {
        if (task.Value.Name == "TileUpdater")
        {
            isTaskRegistered = true;
            break;
        }
    }

    if (!isTaskRegistered)
    {
        RegisterBackgroundTask("TileUpdater", "BackgroundTasks.TileUpdater");
    }
}

As you can see, we are looping through the BackgroundTaskRegistration.AllTasks collection, because we could have multiple Background Tasks running under our application, and in this case, I’m only interested in the one: TileUpdater.  You can also see that I’ve made a call to RegisterBackgroundTask() if the task is not currently registered.

It is up to you how you handle this case, but in my application, I want to make sure that my Background Task is always registered, and if it has been unregistered for some reason, I want to add it back in.  Here’s what my RegisterBackgroundTask() method looks like:

private void RegisterBackgroundTask(string name, string entrypoint)
{
    BackgroundTaskBuilder btb = new BackgroundTaskBuilder();
    btb.Name = name;
    btb.TaskEntryPoint = entrypoint;
    btb.SetTrigger(new SystemTrigger(SystemTriggerType.InternetAvailable, false));

    BackgroundTaskRegistration task = btb.Register();
}

You can see that I’m passing in the name and entrypoint values, but you could certainly hard code those depending on your situation.  Since this application could have multiple Background Tasks, I decided to make this construction a little simpler and pass in some parameters.

In our registration method, we create a BackgroundTaskBuilder object, set the name and entry point, and then determine a SystemTrigger that will kick our Background Task off.  In this case, I’ve chosen the easily testable InternetAvailable trigger.  To try it, we’ll be cutting off our internet access on our machine.

If you ever have a need to unregister your Background Task, it’s pretty simple.  Here’s a sample method, UnregisterBackgroundTask() that you can use to remove the Task.

private void UnregisterBackgroundTask(string name)
{
    foreach (var task in BackgroundTaskRegistration.AllTasks)
    {
        if (task.Value.Name == name)
        {
            task.Value.Unregister(true);
        }
    }
}

In this example, we loop through the Tasks that are registered again, and if we find the one with the name we’re looking for, we call its Unregister() method, confirming with the true parameter.

So we’ve worked through registering and unregistering our Background Task, and we now have specified that our application should kick off our Background Task when the time zone of the machine changes.  Let’s write some actual code in our Background Task class, and then give this thing a test.

Making Your Background Task DO Something

Earlier, we created a file named TileUpdater.cs in our new Windows Runtime Component project, and we left some space to add some code to the Run() method that must be implemented as part of the IBackgroundTask interface.  Here’s what that same file looks like with code to update our Live Tile:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Background;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;

namespace BackgroundTasks
{
    public sealed class TileUpdater : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            XmlDocument tileData = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquareText04);
            XmlNodeList textData = tileData.GetElementsByTagName("text");
            textData[0].InnerText = "Background updates are absolutely amazing. #31daysofwin8";
            TileNotification notification = new TileNotification(tileData);
            notification.ExpirationTime = DateTimeOffset.UtcNow.AddSeconds(30);
            TileUpdateManager.CreateTileUpdaterForApplication().Update(notification);
        }
    }
}

Obviously, we could write a similar Background Task to implement sending a Toast notification, updating the Lock Screen, or other valuable calls to web services for example.

Summary

There’s one more thing to note about Background Tasks: they’re much harder to debug than the code in your actual application.  In fact, Microsoft has written an entire article about exactly how to Debug Your Background Tasks.  I highly recommend reading it.  They have also created a quickstart tutorial called Create and Register a Background Task.

If you would like to download the working sample code from this article, click the icon below:

downloadXAML

Tomorrow, we’re going to shift gears again, and start talking about Navigation.  Specifically, how to navigate between pages in a XAML application, and pass parameters and data as part of that process.  See you then!

downloadTheTools

8 thoughts on “31 Days of Windows 8 | Day #12: Background Tasks

  1. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1230

  2. hi Jeff, I’m a software developer like you, and I’m reading your post about 31 days of Windows Phone 7 these days! that’s great I think. I will read your new post if possible. btw, I’m from China, and thank you for sharing.

  3. Pingback: 31 Days of Windows 8 | Day #12: Background Tasks

  4. Hi. Sample doesn’t work!You must add BackroundTasks to the reference and add “using BackroundTasks” to the MainPage.cs.
    Sorry for bad eng.

  5. Hi ! Thanks for the example! but i can’t make it work! 😦 i do what Sheva wrote, but still nothing, any help? 🙂
    I’m a developer from Perú! 🙂

  6. Pingback: 31 días de Windows 8 | Día 12: Tareas en segundo plano | La Liga Silverlight

  7. a ready working Sample would be greatly appreciated. keep up the good work.

  8. Hi! Thank you for this really simple article on this complex topic. It helped me a lot in my current win 8 dev project. Thanks again! 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s