Tag: ScheduledActionService

EvenTiles from Start to Finish–Part 12

In the previous episode of this series about how to develop a Windows Phone application from scratch we talked about debugging a PeriodicTask. Before digging deeper into exchanging data between an application and its PeriodicTask, we need to talk a little more about scheduling the PeriodicTask and about expiration of a PeriodicTask.

Going back to part 10 of the EvenTiles series, the PeriodicTask was created inside the MainPage.xaml.cs file in a method called StartPeriodicAgent. This private method takes care of stopping a currently active agent before creating a new one. It also handles an exception that might be thrown when an attempt is made to start a new PeriodicTask while the user has disabled background processing for the EvenTiles application, which they can do from inside the Phone Settings.

However, after submitting EvenTiles to Marketplace, I noticed an exceptionally high crash count in the application (as you can see from my AppHub dashboard). Since I want to share all details about developing this application, but also about the application’s life cycle, it is only fair to share the number of crashes to date, a number I am not proud off.

image

For starters, the first version of EvenTiles called LaunchForTest in release mode which results in a thrown exception as shows up in the call stack of various crash incidents. Also, the application does not count on other applications making use of background agents on a particular device. To preserve memory, but mainly battery power on the device, the number of background agents that can run at the same time is limited. It varies depending on the hardware capabilities of the device and might differ between devices, but it is a small number and therefore the limit can easily be reached. When this limit is reached, a SchedulerServiceException will be thrown whenever you attempt to add a periodic task. Of course you much handle this exception to prevent your application against crashing, since you are adding your periodic task from inside your application.

So, to create a periodic task, the following code should be used (which is an extension to the code that we used in part 10 of the series):

Correctly adding the agent
  1. private void StartPeriodicAgent()
  2. {
  3.     RemovePeriodicAgent();
  4.  
  5.     var evenTilesPeriodicTask = new PeriodicTask(evenTilesPeriodicTaskName);
  6.     evenTilesPeriodicTask.Description = "EvenTilesPeriodicTask";
  7.  
  8.     try
  9.     {
  10.         ScheduledActionService.Add(evenTilesPeriodicTask);
  11. #if DEBUG_TASK
  12.         ScheduledActionService.LaunchForTest(evenTilesPeriodicTaskName, TimeSpan.FromSeconds(30));
  13. #endif
  14.         App.PeriodicTaskScheduled = true;
  15.     }
  16.     catch (InvalidOperationException ex)
  17.     {
  18.         if (ex.Message.Contains("BNS Error: The action is disabled"))
  19.         {
  20.             MessageBox.Show("Background agents for this application are disabled.");
  21.         }
  22.     }
  23.     catch (SchedulerServiceException)
  24.     {
  25.         MessageBox.Show("Can't schedule your background agent. There might be too many background agents enabled. You can disable background agents through the phone's settings application.");
  26.     }
  27. }

If you take a look at how a periodic task is created you will also see that a App.PeriodicTaskScheduled is set to true. This static property is maintained in the App.xaml.cs file, its value is stored / retrieved from the IsolatedStorageSettings (see part 5 of EvenTiles for more information).

The reason to add this boolean property is to find out if the application did schedule a PeriodicTask. If a PeriodicTask was added for the application, you must realize that the PeriodicTask will age and eventually it will expire unless it is rescheduled by the application. A PeriodicTask will expire if it has not been rescheduled for 14 days from the time it was scheduled. Since the application is responsible for adding a PeriodicTask, it means that the PeriodicTask will only continue to run if the application is activated at least once every two weeks and if the application makes sure to reschedule the PeriodicTask. The approach that EvenTiles takes right now is to check if at some time a PeriodicTask was scheduled. If so, it will be rescheduled as soon as the EvenTiles’ MainPage is created.

NOTE: We could have used another way to determine if a PeriodicTask was scheduled, for instance by verifying if a SecondaryTile is currently available on the StartScreen.

Making use of IsolatedStorageSettings, we will add logic to the app.xaml.cs file to properly store and retrieve the App.PeriodicTaskScheduled property when the application is started, activated, deactivated and terminated.

To begin, a new property and a new const string to identify the value in the IsoloatedStorageSettings are created in app.xaml.cs as follows:

  1. public const string keyPTScheduled = "K_PTS";
  2.  
  3. public static bool PeriodicTaskScheduled { get; set; }

In the constructor, the PeriodicTaskScheduled property is explicitly initialized to false. Finally, the value of PeriodicTaskScheduled is stored / retrieved in the various application life cycle events:

Store/Retrieve property value
  1. // Code to execute when the application is launching (eg, from Start)
  2. // This code will not execute when the application is reactivated
  3. private void Application_Launching(object sender, LaunchingEventArgs e)
  4. {
  5.     if (appSettings.Contains(keyPTScheduled))
  6.     {
  7.         PeriodicTaskScheduled = (bool)appSettings[keyPTScheduled];
  8.     }
  9.  
  10.     if (!appSettings.Contains(keyActSecBackContent))
  11.     {
  12.         appSettings[keyActSecBackContent] = DefaultSecBackContent;
  13.     }
  14.     ActualSecBackContent = (string)appSettings[keyActSecBackContent];
  15. }
  16.  
  17. // Code to execute when the application is activated (brought to foreground)
  18. // This code will not execute when the application is first launched
  19. private void Application_Activated(object sender, ActivatedEventArgs e)
  20. {
  21.     if (!e.IsApplicationInstancePreserved)
  22.     {
  23.         PeriodicTaskScheduled = (bool)appSettings[keyPTScheduled];
  24.         ActualSecBackContent = (string)appSettings[keyActSecBackContent];
  25.     }
  26. }
  27.  
  28. // Code to execute when the application is deactivated (sent to background)
  29. // This code will not execute when the application is closing
  30. private void Application_Deactivated(object sender, DeactivatedEventArgs e)
  31. {
  32.     appSettings[keyPTScheduled] = PeriodicTaskScheduled;
  33.     appSettings[keyActSecBackContent] = ActualSecBackContent;
  34. }
  35.  
  36. // Code to execute when the application is closing (eg, user hit Back)
  37. // This code will not execute when the application is deactivated
  38. private void Application_Closing(object sender, ClosingEventArgs e)
  39. {
  40.     appSettings[keyPTScheduled] = PeriodicTaskScheduled;
  41.     appSettings[keyActSecBackContent] = ActualSecBackContent;
  42. }

Finally, we will use this property inside the MainPage.xaml.cs file when the page is constructed to determine if we need to reschedule a PeriodicTask:

Rescheduling PeriodicTask?
  1. public MainPage()
  2. {
  3.     InitializeComponent();
  4.     if (App.PeriodicTaskScheduled)
  5.     {
  6.         StartPeriodicAgent();
  7.     }
  8. }

Each time the PeriodicTask is scheduled, the App.PeriodicTaskProperty is set to true and a Secondary Tile is created. If the Secondary Tile is removed, the App.PeriodicTaskProperty is set to false as well.

The following video shows you how to modify the existing EvenTiles project to improve the way the PeriodicTask is scheduled as well as the functionality needed to reschedule the PeriodicTask:

Rescheduling a PeriodicTask

If you want to take a look at the source code that we have available for EvenTiles so far, you can download the entire solution belonging to this episode:

Download EvenTiles Episode 12 Source Code

After downloading and unzipping the sample code, you can open the EvenTiles solution in Visual Studio 2010 Express for Windows Phone. You must have the Windows Phone SDK 7.1 installed on your development system to do so. If you have a developer unlocked phone you can deploy the application to your phone, if you don’t have a developer unlocked phone you can still experiment with this application inside the emulator.

EvenTilesIf you want to see EvenTiles already in action on your Windows Phone, you can also install the latest version from Marketplace. Remember that this application is not meant to be extremely useful, although it contains similar functionality that “serious” applications have. Just go ahead and get your free copy of EvenTiles from Marketplace at this location: http://www.windowsphone.com/en-US/search?q=EvenTiles (or search on your phone for EvenTiles in the Marketplace application).

When EvenTiles continues with part 13, you will learn how to exchange data between an application and its background agent.

EvenTiles from Start to Finish–Part 11

In the previous episode of this series about how to develop a Windows Phone application from scratch we started talking about using a PeriodicTask to perform background processing for our application. You learned how to create a Windows Phone Scheduled Task Agent, a separate project that became part of the EvenTiles solution to host a PeriodicTask. You also learned how the PeriodicTask relates to the EvenTiles to enable background processing for the application. In this episode of EvenTiles we will take a look at how to debug the PeriodicTask.

When you have added a PeriodicTask to your application you may have noticed that the behavior of Visual Studio’s debugger did change. Instead of detaching the debugger if you terminate the application, the debugger remains attached. This allows you to debug the PeriodicTask when the application is no longer executing. This is of course important because typically the PeriodicTask executes without our application being active. Under normal circumstances, a PeriodicTask will run once every 30 minutes for a few seconds. This schedule can not be changed for released applications and is determined by the operating system. Of course debugging a PeriodicTask would be unproductive in this way. Therefore there is a possibility to run your PeriodicTask more frequent under test.

If you take a look at the ScheduledActionService class, you will see that it contains a static method called LaunchForTest. This method allows you to schedule a Periodic Task to run at the time you specify. Since you will only use this method for testing Periodic Tasks, draining the battery by frequently executing code in the background is not really an issue. However, you will must not forget to remove the call to LaunchForTest in your production code. You can for instance do this by making use of conditional compilation. What I like to do is to define a separate symbol (to be used in combination with DEBUG) to control execution of LaunchForTest. Usually in Debug mode you want to test your Periodic Task frequently, but by defining a separate symbol, you can also easily disable calling LaunchForTest, even in Debug mode. The following code fragment defines the DEBUG_TASK constant:

Conditionally defined constant
  1. #if DEBUG
  2. #define DEBUG_TASK
  3. #endif

Since this constant is not defined in Release mode, you don’t have to worry about accidentally adding a call to LaunchForTest in your released application. If you want to test your Periodic Agent with a normal schedule in Debug mode, you can simply change the name of the constant, for instance into NDEBUG_TASK. To make sure that the Periodic Agent will be called more frequent then usual, you can make use of the following code (inside the #if and #endif directives):

Calling Periodic Agent faster
  1. private void StartPeriodicAgent()
  2. {
  3.     RemovePeriodicAgent();
  4.  
  5.     evenTilesPeriodicTask = new PeriodicTask(evenTilesPeriodicTaskName);
  6.     evenTilesPeriodicTask.Description = "EvenTilesPeriodicTask";
  7.  
  8.     try
  9.     {
  10.         ScheduledActionService.Add(evenTilesPeriodicTask);
  11. #if DEBUG_TASK
  12.         ScheduledActionService.LaunchForTest(evenTilesPeriodicTaskName, TimeSpan.FromSeconds(30));
  13. #endif
  14.     }
  15.     catch (InvalidOperationException ex)
  16.     {
  17.         if (ex.Message.Contains("BNS Error: The action is disabled"))
  18.         {
  19.             MessageBox.Show("Background agents for this application are disabled.");
  20.         }
  21.     }
  22. }

As a result, the Periodic Task will now be executed approximately 30 seconds after this statement is executed. After that, the Periodic Task will execute on its normal 30 minute schedule, unless you add the call to LaunchForTest in the DoInvoke method of the Periodic Task as well:

Relaunching Periodic Agent
  1. protected override void OnInvoke(ScheduledTask task)
  2. {
  3.     //TODO: Add code to perform your task in background
  4.  
  5. #if DEBUG_TASK
  6.     ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(30));
  7. #endif
  8.  
  9.     NotifyComplete();
  10. }

The following video shows you how to use the LaunchForTest method inside the EvenTiles application and how to make use of the Visual Studio debugger to test the Periodic Agent:

Debugging a Windows Phone Application’s PeriodicTask using LaunchForTest.

Of course the functionality of the Periodic Agent is still to be determined. In part 12 of EvenTiles we will work on adding functionality for the Periodic Agent.

EvenTiles from Start to Finish–Part 10

In the previous episode of this series about how to develop a Windows Phone application from scratch we talked about creating a Secondary Tile programmatically inside our application and showing different content on both the front and the back of the Secondary Tile.

This time we will introduce the concept of Background Agents for Windows Phone. A Background Agent is a piece of application code that can execute, even when the application is not running. Background Agents can be used to periodically perform some actions. Depending on the type of action and the type of scheduling, Background Agents can be of type PeriodicTask (which runs regularly for short amounts of time) or of type ResourceIntensiveTask (which runs for a longer amount of time, but not on a regular interval). Each application can have at most one PeriodicTask and one ResourceIntensiveTask. There are restrictions in using both PeriodicTask and ResourceIntensiveTask. One of the more important things to keep in mind is that a PeriodicTask will run approximately every 30 minutes for at most a couple of seconds, and it will continue running roughly twice an hour for 14 days in a row (assuming the PeriodicTask does not crash). If the application has not renewed the PeriodicTask within those 14 days, the PeriodicTask will be removed from the schedule. Thinking about it, that makes sense. If a user is not using your application for such a long time, it is probably not necessary to continue executing code for that application in the background.

For EvenTiles we will make use of a PeriodicTask, to allow updating of our Secondary Tile on a regular interval. Since updating the Secondary Tile is a relatively simple action, this is a perfect candidate for a PeriodicTask. In this way we can bring our Secondary Tile to life (after all, things will change to it on the start screen of the user’s phone), regardless of the execution state of our application. This technique can for instance be used to update weather information, or number of newly available emails to simply keep the user informed. In our sample application, we will use a PeriodicTask to simply display different strings on the back of the Secondary Tile. The reason to chose something so simple is to be able to concentrate on the bare functionality of the PeriodicTask, its relation to the application and ways to exchange data between the application and its Periodic Task.

To make use of a PeriodicTask, we need to add a new project to our solution. Visual Studio already contains a template for a Windows Phone Scheduled Task Agent, as shown in the next figure:

image

In the newly created PeriodicTask you will find a method called OnInvoke. That is the method into which you will add the functionality you like to have executed in the background. It is important to call the NotifyComplete method as last statement inside your OnInvoke method. Each time your code executes, it will execute in a separate thread. Since the PeriodicTask runs independent from the application (once the application has started the PeriodicTask), it can not update the User Interface of the application it belongs to.

To be able to start the PeriodicTask from inside your application, the first thing you will do is add a reference to the PeriodicTask in your application’s project:

image

When you have added the reference to the PeriodicTask, you have effectively made a connection between it and the application. This is visible inside the WPAppManifest.xml file:

PeriodicTask in Manifest
  1. <Tasks>
  2.   <DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
  3.   <ExtendedTask Name="BackgroundTask">
  4.     <BackgroundServiceAgent Specifier="ScheduledTaskAgent"
  5.                             Name="EvenTilesScheduledTaskAgent"
  6.                             Source="EvenTilesScheduledTaskAgent"
  7.                             Type="EvenTilesScheduledTaskAgent.ScheduledAgent" />
  8.   </ExtendedTask>
  9. </Tasks>

The next thing that needs to be done is starting the PeriodicTask from inside the application. Of course it is good practice to keep the user in control, so we are going to create the PeriodicTask as a result of a user action. In episode 9 of EvenTiles we added a button to the MainPage to create a Secondary Tile. Since we want this Secondary Tile to change its backside text regularly (even without the application being active), it makes sense to create the PeriodicTask as part of the same Click event handler. The code to create and to remove the PeriodicTask looks like this:

Create and Remove PeriodicTask
  1. private void StartPeriodicAgent()
  2. {
  3.     RemovePeriodicAgent();
  4.  
  5.     evenTilesPeriodicTask = new PeriodicTask(evenTilesPeriodicTaskName);
  6.     evenTilesPeriodicTask.Description = "EvenTilesPeriodicTask";
  7.  
  8.     try
  9.     {
  10.         ScheduledActionService.Add(evenTilesPeriodicTask);
  11.     }
  12.     catch (InvalidOperationException ex)
  13.     {
  14.         if (ex.Message.Contains("BNS Error: The action is disabled"))
  15.         {
  16.             MessageBox.Show("Background agents for this application are disabled.");
  17.         }
  18.     }
  19. }
  20.  
  21. private void RemovePeriodicAgent()
  22. {
  23.     var runningPeriodicTask = ScheduledActionService.Find(evenTilesPeriodicTaskName) as PeriodicTask;
  24.     if (runningPeriodicTask != null)
  25.     {
  26.         ScheduledActionService.Remove(evenTilesPeriodicTaskName);
  27.     }
  28. }

Note how we make use of ExceptionHandling to catch an InvalidOperationException. This exception will typically be thrown if the user has disabled background processing for our application, which they can do from inside the Phone Settings. The following picture shows how the user can enable / disable background processing for our application:

image

Calling the methods to create / remove our PeriodicTask from inside our Click event handler is of course a simple action, although you should note that we create the PeriodicTask before creating a Secondary Tile. The reason for that is to allow the PeriodicTask to display a MessageBox to the user in case of problems. By first creating the Secondary Tile we force our application to immediately go to the background, and with that, not being able to show the MessageBox to the user.

Starting/Stopping Agent
  1. private void btnInstall_Click(object sender, RoutedEventArgs e)
  2. {
  3.     if (secondaryTileInstalled)
  4.     {
  5.         var secondaryTile = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains("TileId=Secondary"));
  6.         if (secondaryTile != null)
  7.         {
  8.             RemovePeriodicAgent();
  9.             secondaryTile.Delete();
  10.             btnInstall.Content = txtInstallTile;
  11.             secondaryTileInstalled = false;
  12.         }
  13.     }
  14.     else
  15.     {
  16.         StartPeriodicAgent();
  17.         StandardTileData NewTileData = new StandardTileData
  18.         {
  19.             BackgroundImage = new Uri("Background.png", UriKind.Relative),
  20.             Title = "EvenTiles",
  21.             Count = 0,
  22.             BackBackgroundImage = new Uri("BackBackTile.png", UriKind.Relative),
  23.             BackTitle = "EvenTiles",
  24.             BackContent = App.ActualSecBackContent
  25.         };
  26.         ShellTile.Create(new Uri("/MainPage.xaml?TileId=Secondary", UriKind.Relative), NewTileData);
  27.     }
  28. }

Since we did not add functionality to our PeriodicTask, it will wake up every 30 minutes to immediately terminate again, because the only thing we are doing inside the PeriodicTask’s OnInvoke method is calling the NotifyComplete method:

An ‘Empty’ PeriodicTask
  1. protected override void OnInvoke(ScheduledTask task)
  2. {
  3.     //TODO: Add code to perform your task in background
  4.     NotifyComplete();
  5. }

I strongly encourage you to take a look at the following video, that shows all the functionality we have so far in action:

PeriodicTask for Background Processing inside a Windows Phone Application

One thing is annoying in our solution so far. If we want to debug our PeriodicTask, we would have to wait 30 minutes each time until code in the PeriodicTask will be executed. How to overcome this problem will be topic of part 11 of our ongoing series around EvenTiles.