Mobile Zone is brought to you in partnership with:

Den is a DZone Zone Leader and has posted 460 posts at DZone. You can read more from them at their website. View Full User Profile

Scheduling tasks on Windows Phone 7

11.13.2010
| 18474 views |
  • submit to reddit

There are a multitude of tasks in an application that sometimes should be scheduled for later execution. Normally, the approach some developers might take is track the time internally - store the time value at the moment and then set up a timer that would count to a specific number and then execute an action. Generally, it is a plausible solution but at the end of the day it will be an additional layer that should be integrated with existing code and might cause problems when it comes to introducing some modifications in existing blocks that can break the execution mechanism.

Instead, you could use the built-in scheduling mechanism - included in Microsoft.Phone.Reactive. The Scheduler class allows you to defer execution of pretty much everything you need. You can either directly operate with Scheduler or via IScheduler, that will get a thread instance from Scheduler.

Let's look at a specific example. Let's say I have a method I want to execute once 2 seconds elapsed from the moment I started another action. First of all, I need to decide whether I want to run the method on the current (UI) or secondary (background) thread.

Running something on the UI thread isn't the best idea unless you need to interact with various UI components, like controls. But you can do this.

First of all, you have to create an IScheduler instance:

IScheduler scheduler = Scheduler.NewThread;

Notice that I am using a new thread here. There are a few options available here besides NewThread (that will be a separate thread - not linked to the one handling the UI):

NewThread will instantiate a scheduler on a new worker thread.

CurrentThread will execute the scheduled action on the UI thread.

Dispatcher will allow you to interact with UI components without freezing the main UI layout - which is good if you want to pass the output to the UI thread without using a separate invoke call.

Immediate will execute the method in the current thread, but unlike CurrentThread, it will be scheduled for immediate execution.

ThreadPool is pretty obvious and if you've worked with threading in desktop applications before, you know that it is basically a queue of worker thread. On Windows Phone 7, the queue is limited to 25 registered simultaneous worker threads - the rest will be in the queue waiting to be called when a spot becomes available.

NOTE: By the way, you are not allowed to call SetMaxThreads as you could in desktop applications. This is mainly introduced for security and performance reasons.

So now that I have the scheduler instance, I can pass an Action and a TimeSpan:

scheduler.Schedule(new Action(() =>
{
for (int z = 0; z < 1000; z++)
{
Debug.WriteLine(z);
}
}), TimeSpan.FromSeconds(2));

Obviously, I am using a very simple action here to demonstrate the capabilities of the scheduling mechanism - you could pass a much more complex method. The passed Action will be executed every 2 seconds.

But that's not the only thing I can do - I might want to schedule an action that should be executed recursively every specific time interval.

To do this, you need to modify the, Schedule call - specifically for it to conform to this structure:

scheduler.Schedule(Action<Action<TimeSpan>> action, TimeSpan dueTime);

So in my case, I simply use this line:

scheduler.Schedule(new Action<Action<TimeSpan>>(GetThis), TimeSpan.FromSeconds(3));

So it will be scheduled to run in three seconds. Now, the action itself:

void GetThis(Action<TimeSpan> action)
{
Debug.WriteLine("Test");
action(TimeSpan.FromSeconds(3));
}

Notice how I am calling the passed action (that originates in the main scheduling call) with a new TimeSpan - when it is hit again, the action will be called once again and it will be your responsibility to break this loop. It is a pretty convenient way to check for data updates, for example.

As you see in my sample, I am using TimeSpan to explicitly pass the time period. However, I should also mention that instead of TimeSpan you can easily use DateTimeOffset.