Win8RP + VS2012RC時点の情報です
ここを見ながら整理整頓。
Metro スタイル アプリのデータの保存について少し考えてみました。まぁWindows Phone 7アプリでも同じようなことは考えないといけないのですが、ここらへんWindows Phoneアプリ開発のときにさぼってたので今考えます。
一時的に保持するデータとずっと保持するデータ
上記のページでは、ユーザーデータとセッションデータと言う表現を使ってましたが、ユーザーデータというのは、アプリケーションでず〜〜〜っと永続化しておきたいデータで、セッションデータが短期的に保持しておきたいデータっぽいですね。
そして方針としては以下のような方針で保存するのがよさそうです。
ユーザーデータ
Windows.Storage.ApplicationData.Current.LocalSettingsで取得できるApplicationDataContainer型。
この型は、基本的にはちょっとリッチなDictionary
var settings = ApplicationData.Current.LocalSettings; settings.Values["key"] = "value"; var value = (string) settings.Values["key"];
ただ、このValuesプロパティには基本的な型しか代入できません。間違って自作クラスを入れようとすると例外が出てしまいます…。ということで、階層的なデータを保存しようと思ったらちょっとひと手間かけないといけません。
ApplicationDataContainer型からApplicationDataContainer型を取得するためのContainersプロパティがあります。これはIReadOnlyDictionary
var settings = ApplicationData.Current.LocalSettings; var newContainer = settings.CreateContainer("key", ApplicationDataCreateDisposition.Always); newContainer.Values["key"] = "value";
CreateContainerメソッドの第一引数がキーで第二引数がどのようにコンテナ作るかというのを指定します。AlwaysとExistingを指定できて、Alwaysが無かったら作って、あればそれを返す。Existingが、無かったら例外で、あればそれを返すような感じです。あんまり使わないかな…?
ということで、ApplicationDataContainerにApplicationDataContainerを入れ子にしていくことで、複雑なデータ構造でも表現できるようになってます。
セッションデータ
セッションデータは、より短期間なデータを表す感じです。具体的にいうと、OnLaunchedでPreviousExecutionStateがApplicationExecutionState.Terminatedになったときにだけ復元したいデータです。ユーザーから見てどういう状態かというと、Metro スタイル アプリが背後に回った後にメモリが圧迫されるなどの要因で、OSによって終了させられた時に、再度前面にアプリを表示させたときです。
ユーザーから見たら、アプリは終了したんじゃなくて、前回の続きを表示してほしいケースですね。この状態に対応するためのデータの保存場所ということになります。
グローバルなデータはアプリケーションのCommonフォルダにあるSuspensionManagerクラスで管理することが出来ます。SuspensionManager.SessionStateを使ってDictionary
protected override async void OnLaunched(LaunchActivatedEventArgs args) { // 実行中ならアクティブ化するだけで終わり if (args.PreviousExecutionState == ApplicationExecutionState.Running) { Window.Current.Activate(); return; } // Frame内で遷移するページ単位のセッションデータを管理できるようにするおまじない var rootFrame = new Frame(); SuspensionManager.RegisterFrame(rootFrame, "AppFrame"); if (args.PreviousExecutionState == ApplicationExecutionState.Terminated) { // OSによって終了させられた時にはデータの復元 await SuspensionManager.RestoreAsync(); } if (rootFrame.Content == null) { // このとき、必要な情報をナビゲーション パラメーターとして渡して、新しいページを // を構成します if (!rootFrame.Navigate(typeof(MainPage))) { throw new Exception("Failed to create initial page"); } } // フレームを現在のウィンドウに配置し、アクティブであることを確認します Window.Current.Content = rootFrame; Window.Current.Activate(); }
グローバルじゃなくてページ単位のセッションデータを保持したいというときにはLayoutAwarePageクラスを継承してたら、LoadState, SaveStateメソッドのpageState引数のDictionary
LoadStateメソッドの時は、セッションデータがそもそも無いときはpageState引数がnullになることがあるので、そこは注意しましょう。
まとめ
ユーザーデータはApplicationData.Current.LocalSettingsで取得できるApplicationDataContainer型に保存するのが第一候補。
セッションデータは、アプリケーションのテンプレートにあるSuspensionManagerクラスを使うのが第一候補。
こいつらで要件を満たせないときは自分でどうにかしましょう(カスタムファイルに保存するとかetc…)ということでした。