「お気に入り」のデータはローミングフォルダーに書き出すようにしたので、自動的にデバイス間で複製される。複製されるタイミングはアプリから制御できずシステム任せなのだが、実際にやってみると、1分もかからずに複製されることもあれば、30分以上待たされることもある。複製が終わってからアプリを起動した場合は問題ない。しかし、アプリの実行中に複製が発生して「お気に入り」のデータが上書きされることもある。そのときには、複製されたデータをアプリで読み込み直す必要がある。また、アプリが中断状態のときに複製が起きることもあるだろう。その場合には、中断から再開されたときに、複製されたデータをアプリで読み込み直さねばならない。すなわち、次の2つの場合に、「お気に入り」のデータを読み込み直す実装が必要だ。
「お気に入り」のデータを読み込み直すロジック
読み込み直すロジックは、プロジェクトのLogicフォルダーにあるFavoriteStorageクラスに実装する(次のコード)。といっても、既存のLoadDataAsyncメソッドを呼び出すだけだ。
public static async Task ReloadAsync()
{
if (theFeed == null)
{
theFeed = new Feed(FeedTitle);
}
await LoadDataAsync();
}
中断から再開されたときのロジック
中断から再開されたときには、Webサービスからデータを再度ダウンロードするように前回実装してある。このときに「お気に入り」のデータも読み込み直せばよいだろう。プロジェクトのLogicフォルダーにあるDataLoaderクラスに、次のコードのように追加する。
// 【第7回】リロードする
public static async void ReloadStart(DataModel.FeedsData feedsData)
{
// 【第8回】「お気に入り」は常にリロードする
if (feedsData.Feeds.Find(Logic.FavoriteStorage.FeedTitle) != null)
await Logic.FavoriteStorage.ReloadAsync();
// 一定時間間隔内に呼び出された場合はネットワークからリロードしない
double elapsedMinutes = DateTimeOffset.Now.Subtract(_lastLoaded).TotalMinutes;
if (elapsedMinutes < LOAD_INTERVAL_MINUTE)
return;
// インターネット接続がないときは無視する
var connectionProfile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
if (connectionProfile == null && feedsData.IsLoaded)
return;
await LoadAsync(feedsData);
}
ローミングが発生したときのロジック
ローミングによってローミングフォルダー内のファイルが書き換えられたときに、ApplicationDataクラス(Windows.Storage名前空間)のDataChangedイベントが発生する。このタイミングで「お気に入り」データを再読み込みすればよい。その実装は、Appクラス(「App.xaml.cs」ファイル)に行う。
まず、アプリ起動時にイベントハンドラーを結び付ける(次のコード)。
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
// 【第7回】中断→再開時の処理
this.Resuming += OnResuming;
// 【第8回】ローミングデータが同期されたときの処理
Windows.Storage.ApplicationData.Current.DataChanged += Roaming_DataChanged;
……省略……
}
Roaming_DataChangedメソッドではFavoriteStorageクラスのReloadAsyncメソッドを呼び出せばよいのだが、このイベントは別スレッドで呼び出されるので工夫が必要になる。次のコードのように、UIスレッドに結び付けられたDispatcherオブジェクトをあらかじめ取得しておいて、それを介してReloadAsyncメソッドを呼び出さねばならない。
protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
……省略……
// 【第6回】正式なロジックの呼び出しに置き換える
var feedsData = App.Current.Resources["feedsDataSource"] as DataModel.FeedsData;
Logic.DataLoader.LoadStart(feedsData);
// 【第8回】ローミングデータが同期されたときの処理に必要
_dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
Frame rootFrame = Window.Current.Content as Frame;
……省略……
}
// 【第8回】ローミングデータが同期されたときの処理
private Windows.UI.Core.CoreDispatcher _dispatcher;
private async void Roaming_DataChanged(Windows.Storage.ApplicationData sender, object args)
{
if (_dispatcher == null)
return;
// ここは別スレッドで呼び出されるため、UIに影響を及ぼす処理はDispatcherを介して呼び出さねばならない
await _dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
async () =>
await AtmarkItReader.Logic.FavoriteStorage.ReloadAsync()
);
}
以上で、ローミング対応も完成だ。
以上で完成だ。「お気に入り」に追加する機能をテストしてみてほしい。記事表示画面でアプリバーから「お気に入り」に追加できるだろうか? 追加した記事データは、メイン画面と記事一覧画面に表示されるだろうか。
ローミングのテストは、Windows 8.1の環境が2台分以上必要になる。VM上の仮想マシンでも構わない。VS 2013が入っていないPCへこのアプリをインストールする方法は、MSDNの「Windows RT への開発者パッケージのインストール」を参照してもらいたい。インストールできたら、いろんなパターンでローミングをテストしてみよう。
最後に、「お気に入り」に10件ほど登録し、そのデータファイルのサイズをチェックしよう。データファイル「Favorite.xml」は、次のフォルダーにある。
C:¥Users¥{ユーザー名}¥AppData¥Local¥Packages¥{マニフェストの「パッケージ化」タブにあるパッケージ名}¥RoamingState
筆者が試したところでは、お気に入りを10件登録した「Favorite.xml」ファイルのサイズは5KBytes弱であった。このことから、上限値の100件までお気に入りを登録しても必要とするサイズは50KBytes程度であり、ローミングの制限である100KBytesまでにはまだ余裕があるだろうと判断できる。ただし、長いコメントを大量に保存されたら制限を超えることもあるだろう。もしもここの判断を厳密にしたいなら、ファイルを保存した直後にファイルのサイズをチェックし、超えていたら古い記事から削除していくようなロジックとコメント文字列の長さ制限を追加するとよい。
また、テストしていて気付かれたと思うが、記事表示画面で見ているその記事がすでに「お気に入り」に登録したものかどうか分からない。今回実装しなかった削除や編集の機能と合わせて、読者の皆さまへの宿題とさせていただきたい。
今回は、エンドユーザーが入力したコメントを含めて記事データをファイルに保存し、同時に画面にも反映させた。アプリケーションリソースに1つだけデータを持たせ、各画面はそれをデータバインドして表示するというアーキテクチャは、最初に作るときは面倒かもしれないが、今回実装したようにデータの追加や変更を全ての画面に反映させるときには威力を発揮する。
また今回は、ローミングの仕組みを利用した。ローミングはWindowsストアアプリの有用性を高める大きな武器になる。ローミングで上書きされたときの対応がちょっと厄介だが、ぜひうまく活用してほしい。
次回は「効果的に情報を提示する」。スタート画面のタイルに新着記事を表示してみよう。また、バッジやトーストといった表示手段も紹介する予定だ。
Copyright© Digital Advantage Corp. All Rights Reserved.