第8回 入力されたデータを保存する:連載:Windowsストア・アプリ開発入門(3/6 ページ)
ファイルの読み書きについて学び、「お気に入り」の機能を実装してみよう。ファイルの保存場所としてアプリケーションデータ記憶域のローミングを利用する。
「お気に入り」を取得するロジック
「お気に入り」のデータをファイルに読み書きする部分ができたので、次はそれを使って「お気に入り」をファイルから取得するロジックを作ろう。
ファイルを読み出してデシリアライズされたものはFeedItemオブジェクトの配列だ。それをFeedオブジェクトに収めておけば、画面側ではダウンロードしてきたRSSフィードのデータと同様に扱える。GetFavoriteFeedAsyncメソッドを作って、そのFeedオブジェクトを返すことにしよう。
ところで、そのようなファイルを読み出してFeedオブジェクトに収める作業は、どんなときにやればいいだろう? 必要とされた最初の1回だけ行えば、基本的にはよいはずだ(読み込み直す話は後述する)。すると、次のようなコードになる。
   public class FavoriteStorage
{
  public static readonly string FeedTitle = "お気に入り";
  private static Feed theFeed; // アプリ全体で唯一のインスタンス
  public static async Task<Feed> GetFavoriteFeedAsync()
  {
    if (theFeed == null) // 最初に呼び出されたときだけ実行する
    {
      theFeed = new Feed(FeedTitle); // Feedオブジェクトをインスタンス化する
      await LoadDataAsync(); // ファイルから読み出し、Feedオブジェクトに詰め込む
    }
    return theFeed;
  }
  private static async Task LoadDataAsync()
  {
    var feedItems = await LoadAsync(); // 先ほど作ったファイルからデシリアライズするメソッド
    if (feedItems == null || feedItems.Length == 0)
      return;
    theFeed.Items.Clear(); // ←これは後でリロード機能を追加するための措置
    // FeedItemオブジェクトを1件ずつFeedオブジェクトに詰め込む
    foreach(var item in feedItems)
      theFeed.Items.Add(item);
  }
  ……省略……
}
「お気に入り」を追加するロジック
「お気に入り」を追加するときには、同じ記事がすでに入っていたら削除することと、追加後に規定数を超えていたら古いものを削除するという処理も必要なので、ちょっと複雑になる。次のコードのようにAddFeedItemAsyncメソッドを作って、画面からは「お気に入り」に入れたい記事のFeedItemとコメント文字列を渡すようにしよう。
   public class FavoriteStorage
{
  ……省略……
  private const int MaxFavorites = 100; // 最大件数(超えたら古いものを消す)
  public static async Task AddFeedItemAsync(FeedItem item, string comment)
  {
    var feed = await GetFavoriteFeedAsync();
    // 同じ記事がすでに入っていたら削除する
    await RemoveFeedItemAsync(item.Title);
    // お気に入りのFeedItemを生成し、theFeedのItemsの先頭に追加する
    var favoriteFeed = new FeedItem(item.Title, item.Link, item.PubDate)
                            {
                              FavoriteComment = comment,
                            };
    feed.Items.Insert(0, favoriteFeed);
    // 規定数を超えていたら古いものを削除する
    RemoveExcessiveItemsAsync();
    // お気に入りデータをファイルに保存する
    await SaveAsync(feed.Items.ToArray());
  }
  // 記事タイトルを指定して、そのFeedItemを「お気に入り」から削除する
  public static async Task RemoveFeedItemAsync(string articleTitle)
  {
    var feed = await GetFavoriteFeedAsync();
    var target = await FindFeedItemAsync(articleTitle);
    if (target == null)
      return;
    feed.Items.Remove(target);
    await SaveAsync(feed.Items.ToArray()); // メモリから削除したら直ちに保存
  }
  // 記事タイトルが一致するFeedItemを探す
  public static async Task<FeedItem> FindFeedItemAsync(string articleTitle)
  {
    var feed = await GetFavoriteFeedAsync();
    foreach (var item in feed.Items)
      if (string.Equals(item.Title, articleTitle))
        return item;
    return null;
  }
  // 規定数を超えていたら古いものを削除する
  private static async void RemoveExcessiveItemsAsync()
  {
    var feed = await GetFavoriteFeedAsync();
    for (int i = (theFeed.Items.Count - 1); i >= MaxFavorites; i--)
      feed.Items.RemoveAt(i);
    // 注)これはprivateメソッドなので、Saveするタイミングは呼び出し側に任せて大丈夫
    //     そのため、ここではSaveしていない
  }
  ……省略……
}
メソッド内でtheFeed静的メンバー変数を直接使わず、メソッドの先頭でいちいちGetFavoriteFeedAsyncメソッドを呼び出して取得しているのは、publicメソッドはどういう順序で呼び出されるか分からず誤った順序で呼び出される可能性があるので、その予防措置である。
Copyright© Digital Advantage Corp. All Rights Reserved.
