実現したい内容
UWPアプリでバックグラウンド処理を用意し、一定時間間隔でインターネットから画像ファイルを取得し壁紙に設定する。アプリが最小化されSuspend(中断)しても、バックグラウンド処理を継続する。アプリが最小化から復帰したら、バックグラウンド処理から最新の画像ファイルの情報を取得し、UIを更新する。
基本のお作法は、MS文書 に記された内容に従い、周辺のコード群を補足する。
一定時間間隔での処理の実行は、ThreadPoolTimer
を利用できるが、UIを最小化するとthreadがSuspended
になり止まる。止めないためには、バックグラウンド処理での実装が必要。
バックグラウンド処理は、長時間の実行を想定するので、out-of-processのバックグラウンド処理として実装する。
UI側の処理(MainPage)
- バックグラウンド処理の登録
- バックグランド処理完了時の処理
- UI最小化によるSuspendからの復帰まわりの処理
- UI側とバックグラウンド側との情報のやりとり
バックグラウンド処理の登録
- 時間トリガを作成してバックグラウンド処理を登録。
- 完了時の
Completed
イベントにハンドラを登録。ここではOnCompleted
を呼び出す。 - バックグラウンド処理に情報を引き渡すために、
ApplicationData.Current.LocalSettings
にデータを設定。大域変数で情報を引き渡すことが出来る相手ではない。
private BackgroundTaskRegistration _BGTask = null;
private String _BGTaskName = "VolcanoWallpaperBGTask";
// "バックグラウンド処理のプロジェクト名.バックグラウンド処理のクラス名"
private String _BGTaskEntryPoint = "VolcanoWallpaperBG.VolcanoWallpaperBGTask";
private void RegisterBGTimerTask(int hour)
{
// 引数チェックなど
...
if (_BGTask != null)
{
UnregisterBGTimerTask();
}
uint triggerInterval = (uint)hour * 60;
IBackgroundTrigger trigger = new TimeTrigger(triggerInterval, false);
var builder = new BackgroundTaskBuilder();
builder.Name = _BGTaskName;
builder.TaskEntryPoint = _BGTaskEntryPoint;
builder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
builder.SetTrigger(trigger);
BackgroundTaskRegistration task = builder.Register();
_BGTask = task;
task.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
ApplicationData.Current.LocalSettings.Values["currentVolcanoCode"] = _CurrentVolcano.Code;
}
二重登録にならないよう、登録解除処理を準備。
private void UnregisterBGTimerTask()
{
_BGTask?.Unregister(false);
_BGTask = null;
}
バックグラウンド処理完了時の処理
バックグラウンド処理が完了時に発生するOnCompleted
イベントで呼び出される処理を準備。アプリのUI部とは別スレッドになるので、Dispatcher.RunAsync()
でUIを更新。UIが最小化していないときは、こちらが呼び出される。
private async void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
Debug.WriteLine(String.Format("Background task completed: {0} {1}",task.TaskId, task.Name));
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
UpdateUI();
});
}
UIの最小化解除時のイベントハンドラの登録
Application.Current.Resuming
イベントにハンドラを登録。UIの最小化が解除されるときに呼び出される。ここでは、AppResuming
を呼び出す。
public MainPage()
{
this.InitializeComponent();
Application.Current.Suspending += new SuspendingEventHandler(AppSuspending);
Application.Current.Resuming += new EventHandler<Object>(AppResuming);
}
対のApplication.Current.Suspending
イベントも登録しているが、本稿では未使用。
UIの最小化が解除されたときの処理
アプリのUIの最小化が解除されると呼び出される。最小化中にもバックグラウンド処理が動作し、最小化前とは状態が変化しているので、最新の状態でUIを更新する。
private void AppResuming(Object sender, Object e)
{
if (_BGTask != null)
{
UpdateUI();
}
}
バックグラウンド処理からの情報の受け取り
バックグラウンド処理からは、ApplicationData.Current.LocalSettings
を介して情報を受け取る。これらを元にUIを更新する。
public void UpdateUI()
{
// バックグラウンド処理からの情報の受け取り
String folder = (String)ApplicationData.Current.LocalSettings.Values["imgFolder"];
String imgFname = (String)ApplicationData.Current.LocalSettings.Values["imgFilename"];
String wallpaperFname = (String)ApplicationData.Current.LocalSettings.Values["wallpaperFilename"];
// UIの更新処理
...
}
バックグラウンド側の処理
UI側のUWPプロジェクトとは別に、Windowsランタイムコンポーネントのプロジェクトとして作成する。ApplicationData.Current.LocalSettings
を介して、UI側に情報を引き渡す。
public sealed class VolcanoWallpaperBGTask : IBackgroundTask
{
private IBackgroundTaskInstance _TaskInstance;
private BackgroundTaskDeferral _Deferral;
public async void Run(IBackgroundTaskInstance taskInstance)
{
_TaskInstance = taskInstance;
_Deferral = taskInstance.GetDeferral();
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
// 処理の本体
...
// UI側に引き渡す情報の設定
ApplicationData.Current.LocalSettings.Values["imgFolder"] = vi.Folder;
ApplicationData.Current.LocalSettings.Values["imgFilename"] = vi.ImageFilename;
ApplicationData.Current.LocalSettings.Values["wallpaperFilename"] = _FileManager.WallpaperName;
_Deferral.Complete();
}
private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
_Deferral.Complete();
}
}
補足
アプリのUI側とバックグラウンド処理は別プロジェクトになるので、両者で使用する処理はSharedのプロジェクトを設けて共用する。例えば、UIからの指示でもバックグラウンド処理でも画像を取得する機能を設ける場合、画像を取得する処理はSharedのプロジェクトで実装する。