Uncategorized

Windows Phone 8 : Background Agents – Periodic Agent

If you are a desktop or web developer, you are used to being able to decide when and where your code runs. On the phone you do not have that luxury, so you have to let the operating system dictate exactly when you run your application or some background operations. But how does the operating system handle background operations?
Normally when you build a typical phone application, you submit a .xap file with all the code your application requires to launch the application’s user interface. Your application can be launched, but when it is not in the foreground, none of your code will execute.

Background agents enable you to supply some code that is executed periodically by the operating system. This code does not have any user interface but shares information with the main application. The information it can share includes isolated storage and application storage (for example, where the .xap file contents are located), as shown in Figure 1.
Image
Although the main application is an assembly that contains the startup code, a background agent works similarly. The background agent consists of an additional assembly that is included in the main application’s .xap file and contains the code to execute in the background. The main goal of the operating system is to protect the phone from you, the developer. All agents have some specific limitations.

Image
Now that you understand the basic reasons and limitations of using background agents, let’s look at each agent type.

1. Periodic Agent

The periodic background agent is a background agent that is meant to execute some code every 30 minutes. To optimize the battery life of the phone, this can wander as much as 10 minutes earlier or later to align with operating system processes. These processes can run for only a maximum of 25 seconds. To get started, you will need a Schedule Task Agent project in your solution. To add a Scheduled Task Agent project, right-click the solution in the Solution Explorer and select Add | New Project.
After you are in the Add New Project dialog, select the Windows Phone Scheduled Task Agent project type under the Windows Phone section of your language, as shown in Figure 2.

Image
This creates a new project in your solution that contains a single class file:

using Microsoft.Phone.Scheduler;

public class ScheduledAgent : ScheduledTaskAgent
{
  static ScheduledAgent()
  {
    // Subscribe to the managed exception handler
    Deployment.Current.Dispatcher.BeginInvoke(delegate
    {
      Application.Current.UnhandledException += UnhandledException;
    });
  }
  static void UnhandledException(object sender,
    ApplicationUnhandledExceptionEventArgs e)
  {
    if (Debugger.IsAttached)
    {
      Debugger.Break();
    }
  }
  protected override void OnInvoke(ScheduledTask task)
  {
    //TODO: Add code to perform your task in background
    NotifyComplete();
  }
}

The ScheduledAgent class created overrides a single method (OnInvoke) that the operating system calls when the background agent is executed. You should do your work in this method and have the call to NotifyComplete be the last line of code in this method. The NotifyComplete method tells the operating system that your operation is complete. For example, to save a file with the current time in isolated storage (so your UI app can use it), you could do this:

protected async override void OnInvoke(ScheduledTask task)
{
  var folder = ApplicationData.Current.LocalFolder;
  using (var stream =
    await folder.OpenStreamForWriteAsync(“time.txt”,
             CreationCollisionOption.ReplaceExisting))
  {
    var writer = new StreamWriter(file);
    writer.WriteLine(DateTime.Now);
  }
  NotifyComplete();
}

Because this code writes directly to isolated storage for the application, that means the main application can read the file you created here. As shown here, you can call the NotifyComplete method when you have completed your operation. You also might want to know whether the operation fails. You can accomplish this by calling the Abort method:

try
{
  var folder = ApplicationData.Current.LocalFolder;
  using (var stream =
    await folder.OpenStreamForWriteAsync(“time.txt”,
               CreationCollisionOption.ReplaceExisting))
  {
    var writer = new StreamWriter(stream);
    writer.WriteLine(DateTime.Now);
  }
  NotifyComplete();
}
catch
{
  Abort();}

You should call either NotifyComplete or Abort in your agent, to let the runtime (and potentially your application) know whether the task was successfully completed.
When you added the new scheduled agent, the project also reached into the main application and added a new section to the WMAppManifest.xml file:

<Deployment …>
  <App …>
  …
    <Tasks>
      <DefaultTask Name=”_default”
                   NavigationPage=”MainPage.xaml” />
      <ExtendedTask Name=”BackgroundTask”>
        <BackgroundServiceAgent Specifier=”ScheduledTaskAgent”
                                Name=”BackgroundAgent”
                                Source=”BackgroundAgent”
                                Type=”BackgroundAgent.ScheduledAgent”
        />
      </ExtendedTask>
    </Tasks>
    …
  </App>
</Deployment>
Inside the Tasks element, the project item added a section called ExtendedTask, which is responsible for indicating the project and code for any background tasks. The ExtendedTask element is where all agents are registered, including periodic, resource-intensive, and audio agents. Although the ExtendedTask is named, the name is not significant. Inside the ExtendedTask element is a set of elements that reference the different background agent or agents in your application. Each attribute in the BackgroundServiceAgent element has a specific meaning:

  • Name: This is the name of the element, not referenced in code.
  • Specifier: This is the type of agent. The types of specifiers are as follows:

– ScheduledTaskAgent: This is a periodic or resource-intensive task.
– AudioPlayerAgent: This task plays specific songs from a list of audio files.
– AudioStreamingAgent: This task streams audio directly to the phone.

  • Source: This is the assembly name that contains the background agent.
  • Type: This is the type of the class that represents the background agent.
This part of the WMAppManifest.xml file is what links your application to the assembly that contains your background task. This means your background agent must be in a separate assembly (as the separate project would indicate). You still have to do a little more work to make your agent actually run in the background.
Before your application can register the background task, you need to make a reference to the new background project. This just requires you to select Add Service Reference and pick the assembly in the Solution tab.

Image

After your main project has a reference to the background task, you can register it to be executed periodically. To do this, you need to create a new instance of your task using the PeriodicTask class:

// A unique name for your task. It is used to
// locate it in from the service.
var taskName = “MyTask”;
// Create the Task
PeriodicTask task = new PeriodicTask(taskName);
// Description is required
task.Description = “This saves some data to Isolated Storage”;
// Add it to the service to execute
ScheduledActionService.Add(task);

The unique name here is used to locate the service if you need to stop or renew the service, but it is not related to the task name in the WMAppManifest.xml file. After your task is created, you must set the Description property as well (at a minimum). After your PeriodicTask object is constructed, you can add it to the phone by using the ScheduledActionService’s Add method as shown. This will cause your background task to be periodically executed (every 30 minutes).

Periodic Agent Timing
Although the phone attempts to execute your code every 30 minutes, it can be executed as much as 10 minutes early or late depending on the state of the system (for instance, memory, battery, and so on).

You should set the Description property of the PeriodicTask class to something significant. The description is a string that is visible to the end user and that is shown in the background task management UI.

Image

Each periodic task will execute for up to two weeks before it has to be reregistered. The only exception to this is if you are updating your live tile. When you update the live tile (either through the app or through a background agent), this will extend the length of the registration another two weeks. When you launch your app, you should remove and re-create it on every execution of your application:

// A unique name for your task. It is used to
// locate it in from the service.
var taskName = “MyTask”;
// If the task existsvar oldTask = ScheduledActionService.Find(taskName);if (oldTask != null){  ScheduledActionService.Remove(taskName);}
// Create the Task
PeriodicTask task = new PeriodicTask(taskName);
// Description is required
task.Description = “This saves some data to Isolated Storage”;
// Add it to the service to execute
ScheduledActionService.Add(task);

Now that you have your agent registered, you will need to be able to debug it. The problem on the face of it is that you might not want to wait the 30 minutes for your agent to execute. The ScheduledActionService has a way to run the agent immediately so that you can debug it more easily:

var taskName = “MyTask”;
ScheduledActionService.LaunchForTest(taskName,  TimeSpan.FromMilliseconds(250));

The LaunchForTest method takes the name of the task (which you specified earlier when you created the PeriodicTask) and a delay before the task is launched. Lastly, because the background task (in this example) was able to write to isolated storage, you can access that data in your main application anytime you want. The background task and your application simply need to communicate by storing information in these shared locations (local folder, the Internet, or reading from the installation folder).
In addition, you might want to alert the user about new information the background task detected (for example, a new message is available). You can use the ShellToast class to open a toast (or update Live Tiles):

protected override void OnInvoke(ScheduledTask task)
{
  // If the Main App is Running, Toast will not show
  ShellToast popupMessage = new ShellToast()  {    Title = “My First Agent”,    Content = “Background Task Launched”,    NavigationUri = new Uri(“/Views/DeepLink.xaml”, UriKind.Relative)  };  popupMessage.Show();
  NotifyComplete();
}

By using the ShellToast class, you can alert the user that the background task detected something and give her a chance to launch the application. If the main application is currently running, the ShellToast class will not show the pop-up and will be reserved to show when your application is not currently being executed.
Creating your own periodic tasks is an easy way to do simple background processing, be able to alert the user to ongoing events, and allow her to interact with your application. But sometimes you will need a periodic task that consumes more resources. That is where resource-intensive agents come in.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.