Windowsストアアプリは基本はフルスクリーンで実行され、フォアグラウンドのアプリだけがCPUで実行されます。この状態を「実行中」状態といいます。実行中のアプリ以外は「一時停止」状態または「終了」状態となり、これらはCPUで実行されません。
しかし、アプリがフォアグラウンドにいないときでも、バックグラウンドで何か処理を行う必要があるようなケースもあります。 そのようなバックグラウンドでのタスク実行をサポートするWindowsストアアプリの仕組みをバックグラウンドタスクと言います。 代表的なバックグラウンドタスクとしては、下記のような処理があります。
- プッシュ通知
- プレイバックマネージャー(オーディオ再生)
- バックグラウンド転送(ファイルのダウンロードやアップロード)
- ファイル共有コントラクト(アプリ間でのデータ共有)
注意しなければいけないのは、バッテリー消費量を最小限にするために、バックグラウンドタスクは使用できるリソースがひじょうに限定されているという点です。 CPUやネットワークの使用時間の上限が細かく規定されており、一定時間単位に規定時間しかそれらのリソースを使うことができません。このため、バックグラウンドタスクで実行する処理は最低限の処理とする必要があります。
バックグラウンドタスクの実行
バックグラウンドタスクは、1つのトリガーイベントの発生で起動されます。さらに0またはそれ以上のバックグラウンドコンディションが成立したときに実際にバックグラウンドタスクが実行されます。
ここからはマイクロソフトの提供するバックグラウンドタスクのサンプルソースのC#ソースコードをベースに詳細な説明をします。
(1)C#\Tasks\SampleBackgroundTask.cs
バックグラウンドタスクを実行するためのクラスSampleBackgroundTaskを定義します。 バックグラウンドタスクはIBackgroundTaskインタフェースを実装する必要があります。
//
// The namespace for the background tasks.
//
namespace Tasks
{
//
// A background task always implements the IBackgroundTask interface.
//
public sealed class SampleBackgroundTask : IBackgroundTask
....
(2)C#\BackgroundTask\Constants.cs
バックグラウンドタスクのクラス名をSampleBackgroundTaskEntryPointとして定義します。また、バックグラウンドタスクを登録する際に識別するための名前として「SampleBackgroundTaskWithCondition」をSampleBackgroundTaskWithConditionName という定数で定義します。後者は単なる文字列で識別するための名前なので特に何でもかまいません。
namespace BackgroundTask
{
class BackgroundTaskSample
{
....
public const string SampleBackgroundTaskEntryPoint = "Tasks.SampleBackgroundTask";
public const string SampleBackgroundTaskWithConditionName = "SampleBackgroundTaskWithCondition";
....
(3)C#\BackgroundTask\SampleBackgroundTaskWithCondition.xaml.cs
バックグラウンドタスクを登録します。 BackgroundTaskSample内に作成したRegisterBackgroundTask関数内で実際の登録は行います。 引数として(2)で定義したバックグラウンドタスクのクラス名SampleBackgroundTaskEntryPoint、バックグラウンドタスク名SampleBackgroundTaskWithConditionNameをセットします。
また、トリガイベント、バックグラウンドタスクコンディションも引数として渡します。トリガイベントとしてはサンプルではSystemTriggerType.TimeZoneChangeを設定します。 これによりデバイスでタイムゾーンが変更されたときにバックグラウンドタスクのトリガイベントが発生します。 各種トリガイベントの詳細はこちらを参照してください。
また、コンディションとしてはSystemConditionType.InternetAvailableを設定します。 これによりトリガイベントが発生した際、インターネットに接続されている状態のときのみバックグラウンドタスクが実行されます。 インターネットに接続されていない場合は、インターネットに接続されるまでバックグラウンドタスクは実行されません。 コンディションの詳細はこちらを参照してください。
namespace BackgroundTask
{
public sealed partial class SampleBackgroundTaskWithCondition : SDKTemplate.Common.LayoutAwarePage
{
....
private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
{
var task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.SampleBackgroundTaskEntryPoint,
BackgroundTaskSample.SampleBackgroundTaskWithConditionName,
new SystemTrigger(SystemTriggerType.TimeZoneChange, false),
new SystemCondition(SystemConditionType.InternetAvailable));
AttachProgressAndCompletedHandlers(task);
(4)C#\BackgroundTask\Constants.cs
(3)で呼び出されたRegisterBackgroundTask関数の中で実際にバックグラウンドタスクを登録します。 登録はBackgroundTaskBuilderクラスのインスタンスbuilderを生成し、そのBackgroundTaskBuilder.Registerメソッドで登録します。 詳細を説明します。
まず、生成したBackgroundTaskBuilderクラスのインスタンスbuilderのNameプロパティにバックグラウンドタスク名をセット、TaskEntryPoint にバックグラウンドタスクのクラス名Tasks.SampleBackgroundTaskをセットします。 次に、トリガイベントとしてSystemTriggerType.TimeZoneChangeをbuilderのSetTriggerメソッドで設定します。 そして、コンディションとしてSystemConditionType.InternetAvailableをbuilderのAddConditionメソッドで設定します。
最後に実際のバックグラウンドタスク登録です。 builderのRegisterメソッドで登録します。 このときの返値としてBackgroundTaskRegistrationインスタンスが得られるため、これをRegisterBackgroundTask関数の返値として返します。 このインスタンスは(6)(7)で説明するバックグラウンドタスクの各種イベントハンドラの登録に使用します。
namespace BackgroundTask
{
class BackgroundTaskSample
{
public static BackgroundTaskRegistration RegisterBackgroundTask(String taskEntryPoint, String name, IBackgroundTrigger trigger, IBackgroundCondition condition)
{
var builder = new BackgroundTaskBuilder();
builder.Name = name; // "SampleBackgroundTask"
builder.TaskEntryPoint = taskEntryPoint; // IBackgroundTask インタフェースを実装した"Tasks.SampleBackgroundTask"
builder.SetTrigger(trigger); // new SystemTrigger(SystemTriggerType.TimeZoneChange, false)
if (condition != null)
{
builder.AddCondition(condition); // new SystemCondition(SystemConditionType.InternetAvailable)
//
// If the condition changes while the background task is executing then it will
// be canceled.
//
builder.CancelOnConditionLoss = true;
}
BackgroundTaskRegistration task = builder.Register();
....
return task;
}
(5)C#\Tasks\SampleBackgroundTask.cs
バックグラウンドタスクで実際に実行される部分はSampleBackgroundTaskクラス(IBackgroundTaskインタフェース)のRunメソッド内に実装します。
namespace Tasks
{
//
// A background task always implements the IBackgroundTask interface.
//
public sealed class SampleBackgroundTask : IBackgroundTask
{
....
//
// The Run method is the entry point of a background task.
//
public void Run(IBackgroundTaskInstance taskInstance)
{
Debug.WriteLine("Background " + taskInstance.Task.Name + " Starting...");
(6)C#\BackgroundTask\SampleBackgroundTaskWithCondition.xaml.cs
(4)でバックグラウンドタスクを登録したRegisterBackgroundTask関数の返値であるBackgroundTaskRegistrationインスタンスtaskをAttachProgressAndCompletedHandlers関数に渡して(実際にはIBackgroundTaskRegistrationインタフェース)バックグラウンドタスクのイベントハンドラを登録します。実際のAttachProgressAndCompletedHandlers関数内の処理は(7)で説明します。
namespace BackgroundTask
{
public sealed partial class SampleBackgroundTaskWithCondition : SDKTemplate.Common.LayoutAwarePage
{
....
private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
{
var task = BackgroundTaskSample.RegisterBackgroundTask(BackgroundTaskSample.SampleBackgroundTaskEntryPoint,
BackgroundTaskSample.SampleBackgroundTaskWithConditionName,
new SystemTrigger(SystemTriggerType.TimeZoneChange, false),
new SystemCondition(SystemConditionType.InternetAvailable));
AttachProgressAndCompletedHandlers(task);
(7)C#\BackgroundTask\SampleBackgroundTaskWithCondition.xaml.cs
この関数でバックグラウンドタスクの進捗度イベントであるBackgroundTaskRegistration.Progressと、バックグラウンドタスクの完了イベントであるBackgroundTaskRegistration.CompletedにそれぞれイベントハンドラとしてOnProgressとOnCompleted関数を登録します。
namespace BackgroundTask
{
public sealed partial class SampleBackgroundTaskWithCondition : SDKTemplate.Common.LayoutAwarePage
{
....
private void AttachProgressAndCompletedHandlers(IBackgroundTaskRegistration task)
{
task.Progress += new BackgroundTaskProgressEventHandler(OnProgress);
task.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
}
....
///
/// Handle background task progress.
///
///The task that is reporting progress.
///Arguments of the progress report.
private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
{
var progress = "Progress: " + args.Progress + "%";
BackgroundTaskSample.SampleBackgroundTaskWithConditionProgress = progress;
UpdateUI();
}
///
/// Handle background task completion.
///
///The task that is reporting completion.
///Arguments of the completion report.
private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
UpdateUI();
}
以上でサンプルソース内で実装されているトリガイベントとコンディションの登録、バックグラウンドタスク自身の登録、バックグラウンドタスク処理実装部分、イベントハンドラに関連する重要なポイントは説明出来たと思います。詳しい部分は実際のサンプルソースで確認をすると理解は深まると思います。