Part 34: Creating a Background Agent for Scheduled Tasks
Description
Source Code: https://aka.ms/absbeginnerdevwp8
PDF Version: https://aka.ms/absbeginnerdevwp8pdf
At this point, our AroundMe app is missing just one final feature: the ability to randomly change the lock screen to one of the pictures we've selected every few moments, even if the AroundMe app isn't currently running.
This functionality requires we use a Scheduled Task Agent. The Scheduled Task Agent runs in the background and executes at specific intervals even when our program is not in the foreground -- in other words, when it is not the app you're working with on screen. In our case, we'll schedule the task to run every 30 seconds. When the scheduled task executes, it will call into our LockScreenHelper class' SetRandomImageFromLocalStorage() method.
To enable this functionality we will add a new Windows Phone Scheduled Task Agent project to our current solution. This poses a problem ... we will need to execute the code in our LockscreenHelper.cs from our new project. However, currently this file (as well as its dependencies, the FlickrImages.cs and Photo.cs class files) reside in our main project at the moment. We could merely cut, copy and paste the code files so that they reside in both projects, however the better solution (from a code maintenance perspective) would be to create a third project, a Windows Phone Class Library project, that will house the shared code files, then reference it from both projects. We typically want to share code rather than duplicate it so that any changes or updates can be made in one place and shared by all dependents.
Our game plan:
- We'll add a new Windows Phone Scheduled Task Agent project to our Solution
- We'll add a couple lines of code that will call the SetRandomImageFromLocalStorage() method and allow us to test it in the emulator
- We'll add a new Windows Phone Class Library project in our solution and will move our three class files into it that will be shared between the other two projects.
- We'll move those code files into the Windows Phone Class Library, we'll use NuGet to add in Newtonsoft's JSON library and the Microsoft.Net.Http library package, we'll clean up the namespaces and so on.
- We'll create references from the AroundMe project and the Scheduled Task Agent project to our new Class Library project.
- In the main AroundMe project, I'll need to introduce the Scheduled Task Agent to the operating system by launching it when AroundMe starts up, and configure the WMAppManifest.xml to be an extension in order to allow our app to be a Lock screen Background Provider.
- And if all goes well, we'll run it and watch the fireworks.
- I'm not going to submit this app to the store ... we've already seen that process in lesson 23, but I will show you some last steps required before submitting the app to the store, including how to get a token to properly license and use Map Services in your Phone Store app.
1. Add a new Windows Phone Scheduled Task Agent project to our solution called AroundMe.Scheduler
I don't believe I've ever demonstrated how to add a second project to a solution in the C# Fundamentals series. Assuming you do not know how to do this ...
- Right-click the solution name in the Solution Explorer
- Select Add
- New Project ...
The Add New Project dialog appears:
- Select the Visual C# Windows Phone templates
- Select Windows Phone Scheduled Task Agent project template
- Name it: AroundMe.Scheduler ... we'll use a common notation when naming projects, the dot notation, to match what we want the default namespace for our code in this project to have
- Click OK
You should now see a second project in the Solution Explorer. The most important part of this project is the ScheduledAgent.cs class.
Most of code in the ScheduledAgent.cs file is "boiler plate" meaning we will not need to change it, but it must be there in order to create a valid Scheduled Task Agent. However, if you scroll down near the bottom of the file, in line 41 you'll find the OnInvoke() method with a TODO comment. This is where we'll implement our code as follows:
As you can see, I added a TODO. We'll come back here later and add code that will set the random image from local storage. We have a little setup work to do first.
Before we do that, I've added one line of code (with about 10 lines of comments) that explain it's purpose. I copied it from this source:
So, line 61 of the code snippet above:
ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(30));
... is merely for testing purposes in the Phone Emulator. This allows developers to watch the behavior of the task every 30 seconds. Otherwise, as we'll learn in a moment, when our app is deployed to a real Phone device, it will only run once every 20 to 40 minutes. More about that in just a moment.
As the comments above it explain, we need to either remove this line of code, or at least wrap it in an if statement like this:
if (Debugger.IsAttached) {
}
The original article references this additional background information:
https://msdn.microsoft.com/en-US/library/windowsphone/develop/hh202942(v=vs.105).aspx
That article is very important for our purposes, and if you think you need to do some background processing or scheduled processing, you MUST read that article. In a nutshell, there are two types of background tasks: ResourceIntensiveTasks and PeriodicTasks. Resource Intensive tasks run in the background because they may take a long time to complete ... they're processor intensive. PeriodicTasks run at set intervals. In our case, we're creating a PeriodicTask.
There are different rules and constraints depending on the type of background task we're working with. Both ResourceIntensiveTasks and PeriodicTasks share the following constraints:
- An application may have only one background agent, and only one instance of the agent runs at a time.
- We're limited by which of the Phone's APIs we can utilize from a background task
- We're limited by the amount of the phone's resources we can use ... no more than 11 megabytes for an application like ours
- Our scheduled task will only work for two weeks before it needs to be rescheduled by re-running the AroundMe app
- If our app crashes twice in a row, it will be unscheduled by the operating system
In our case, since we're working with PeriodicTasks, we need to be aware of a few additional things: - Our task will run about every 30 minutes, however the phone's operating system decides when to run the tasks. In fact, it might run ALL scheduled tasks at the same time because it's more efficient to use the phone's battery once every 30 minutes than a bunch of times during that same period for each individual Scheduled Task that wants to run. So, that 30 minute time frame can drift as much as 10 minutes in either direction. So, when we deploy our AroundMe app to a phone, it will change image every 20 to 40 minutes or so.
- Our Scheduled task can only run for 25 seconds before it is shut down by the operating system. That shouldn't affect us, but we should be aware of that for future reference.
- If the battery is low and the phone goes into Battery Saver mode, then our Scheduled Task may not run at all. If you have a Windows Phone 8 and your batter gets low, you'll see a little heart icon over the battery meaning that it has shut down scheduled tasks, turned off some of the functionality of the phone like the GPS and Bluetooth radio and more. Users can configure how aggressive they want Battery Saver to be in the Settings screen. I have a battery monitoring app on my start page, and I was getting low on battery, then I noticed that Battery Saver mode kicked in and I had 20 hours left. That's because it was throttling what was going on in the background. So, be aware of that when you create your own Scheduled Tasks.
- Finally, depending on each phone's configuration, there may be a limit to how many background agents can run at the same time. A few days ago I hit that limit and it asked me to choose some background tasks to shut down because the phone was low on memory.
So, if you plan on submitting a phone to the Store you'll need to be willing to support users. If you want to support your users, you'll need to know a little about how the phone and the operating system work with your app. If the user complains that their background is not changing often enough, you might want to ask a few questions about how many apps are currently running.
To see what's running in the background, go