2. Resource-Intensive Agent
Like a periodic agent, a resource-intensive
agent is a repeatable task that performs some discrete process in the
background. Unlike the periodic agent, though, the resource-intensive
agent is not meant to be executed very often. In fact, there are a
strict set of rules as to when resource-intensive agents are executed.
These agents are meant to be able to run for a longer period (up to 10
minutes) and consume more resources (for instance, network, and memory).
But to allow your agent to be executed, the operating system must only
allow it when doing so is not detrimental to the phone itself. To that
end, the criteria for executing a resource-intensive agent include
• On external power
• When using a noncellular network (for example, Wi-Fi or plugged into a PC)
• When the minimum battery level is 90%
• When the device must be screen-locked
• When no phone call is active
These rules should imply the fact that
resource-intensive agents are meant for syncing large amounts of data or
processing that will be accomplished occasionally. These agents are
often executed only once a day, at most. Deciding whether to use an
agent (or deciding to use a periodic agent or resource-intensive agent)
can increase the overall usefulness of your application.
If the criteria for executing a
resource-intensive agent change while the agent is being executed (for
instance, a phone call comes in or the phone is removed from external
power), the resource-intensive agent will immediately be aborted to
allow the user full access to the phone.
Warning
Resource-intensive agents have so many
requirements to enable them to be executed that some users will never be
able to execute these agents. For example, users who don’t dock their
phone with a PC or use Wi-Fi will never execute a resource-intensive
agent.
Both resource-intensive and periodic agents are
scheduled agents. So whether you’re adding a periodic or a
resource-intensive agent (or even if you need both), you will have a
single Scheduled Task Agent project .
Registering a resource-intensive agent is virtually identical to registering a periodic agent:
// A unique name for your task. It is used to
// locate it in from the service.
var taskName = "IntensiveTask";
// If the task exists
var oldTask = ScheduledActionService.Find(taskName);
if (oldTask != null)
{
ScheduledActionService.Remove(taskName);
}
// Create the Task
ResourceIntensiveTask task = new ResourceIntensiveTask(taskName);
// Description is required
task.Description = "This does a lot of work.";
// Add it to the service to execute
ScheduledActionService.Add(task);
The only real difference is that the class you create is an instance of ResourceIntensiveTask
(instead of PeriodicTask
).
By specifying that the new task is a resource-intensive task, the
operating system will know to execute the agent only when the phone is
ready for a resource-intensive operation (for example, it is in a state
as defined by the previously mentioned limitations).
You can test resource-intensive agents in the same way as well, by calling the ScheduledActionService
’s LaunchForTest
method:
var taskName = "IntensiveTask";
ScheduledActionService.LaunchForTest(taskName,
TimeSpan.FromMilliseconds(10));
You might want to have both a periodic and a
resource-intensive task registered for the phone. The problem is that an
application can have only a single background agent (the Scheduled Task
Agent project) associated with an application. You can register one
(and only one) of each type of scheduled task. This means you can have a
periodic task and a resource-intensive task for your application, but
because there is only one agent, you must discriminate which type of
task is being called in your agent by checking the task type, like so:
public class ScheduledAgent : ScheduledTaskAgent
{
protected override void OnInvoke(ScheduledTask task)
{
if (task is ResourceIntensiveTask)
{
DoHeavyResources();
}
else
{
DoPeriodic();
}
NotifyComplete();
}
// ...
}
In this way, you can determine the type of task the OnInvoke
is meant to execute. You could discriminate by name as well, but
because you can have only one of each type, testing by object type is
just as effective.