2012年4月28日土曜日

Windows8 でのデータ保存

さてGoogle+に対してのOAuthアクセスは作成しましたが、
アクセストークン等のアプリケーションデータを保存しよーと思ったら、
WindowsPhone的なIsolatedStorageFileStreamがない事に気付きました。

そう言われるとデータベースとか、スマートフォン系の特殊なアクセスばっかりで
「設定ファイル」何かを作ってデータを永続化してないなぁと思ったので
設定ファイルを作ってみる事にした。

シリアライズ可能なオブジェクト
シリアライズ可能なクラスを作成します。
  1. private static Settings _settings;  
  2. public static Settings Settings {  
  3.     get { return _settings; }  
  4. }  
私はAppにstaticなメンバを作成しておきました。 この中にアクセストークンのデータを残すようにしておきます。 ※アクセストークン(string)、リフレッシュトークン(string)、有効期限(現在時刻から足し込んだDateTime)
データの保存
データの保存は以下の通りで行いました。
  1. async static private Task<StorageFile> GetSettingFile()  
  2. {  
  3.     var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;  
  4.     StorageFile file = await folder.CreateFileAsync("settings.xml",CreationCollisionOption.OpenIfExists);  
  5.     return file;  
  6. }  
  7.   
  8. async static public void SaveSetting()  
  9. {  
  10.     var file = await GetSettingFile();  
  11.     var serial = new XmlSerializer(typeof(Settings));  
  12.     using ( var tWriter = new StringWriter() ) {  
  13.         serial.Serialize(tWriter, _settings);  
  14.         using (var stream = await file.OpenAsync(FileAccessMode.ReadWriteUnsafe))  
  15.         {  
  16.             var outputStream = stream.GetOutputStreamAt(0);  
  17.             using (var writer = new DataWriter(outputStream))  
  18.             {  
  19.                 writer.WriteString(tWriter.ToString());  
  20.                 await writer.StoreAsync();  
  21.             }  
  22.         }  
  23.     }  
  24. }  
「Windows.ApplicationModel.Package.Current.InstalledLocation」で インストールしたディレクトリを取得する事ができます。 他にドキュメント内とかでも保存できるのですが、 他の場所に保存する場合は、パーミッション(Package.appxmanifest)が必要になるようです。 ※また機会あったら書きます。 CreateFileAsync()を使用していますが、 同期的に取得するのでawaitで呼び出しています。 第2引数の「CreationCollisionOption.OpenIfExists」は存在しない場合作成してくれます。 ※これを付けないとsettings(2).xmlとかをモリモリ作ります。 あとはSettingsオブジェクトをシリアライズして保存しています。
データの取得
  1. async private void LoadSetting()   
  2. {  
  3.     var file = await GetSettingFile();  
  4.     using (var stream = await file.OpenAsync(FileAccessMode.Read))  
  5.     {  
  6.         var inputStream = stream.GetInputStreamAt(0);  
  7.         using (var reader = new DataReader(inputStream))  
  8.         {  
  9.             uint size = (uint)stream.Size;  
  10.             await reader.LoadAsync(size);っd  
  11.             string data = reader.ReadString(size);  
  12.             if (!data.Equals(""))  
  13.             {  
  14.                 using (var textReader = new StringReader(data))  
  15.                 {  
  16.                     XmlSerializer serial = new XmlSerializer(typeof(Settings));  
  17.                     _settings = (Settings)serial.Deserialize(textReader);  
  18.                 }  
  19.             }  
  20.             else  
  21.             {  
  22.                 _settings = new Settings();  
  23.             }  
  24.         }  
  25.     }  
  26. }  
後は同様に読み込むだけですね。
保存したデータ
  1. <?xml version="1.0" encoding="utf-16"?>  
  2. <Settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
  3.   <AccessToken>  
  4.     <accessToken>ya29.AHES6ZQ0-H7cotFnLdVAcZ5CVz280mBarXy4tUn7-_Bs-AE</accessToken>  
  5.     <refreshToken>1/x8SHm9FaHD299fdZSNNyme2m3X2Up_Ki90pcUc2Y2Iw</refreshToken>  
  6.     <expiresIn>2012-04-28T21:48:28.55985+09:00</expiresIn>  
  7.   </AccessToken>  
  8. </Settings>  
こんな感じで残ってました。 ※AccessTokenクラスで保存しています。 開発中は、 「C:\Users\(ユーザ名)\Documents\Visual Studio 11\Projects\GooglePlus\GooglePlus\bin\Debug\AppX」 って位置にありました。 リリースすると 「C:\Users\(ユーザ名)\AppxLayouts\(アプリのID)」 のようです。
感想
保存方法がかなりWindowsPhoneと違いました。 現状開発中で気になっているのは Suspendingのイベントに対して、保存処理を行ったんですけど、 開発中だからか、動作せずにStaticで他の画面から呼び出している状態になってしまいました。
何か間違ってるのかな?

await async知らなかったので呼び出した時のエラー原因がわからなかったです。

1 件のコメント:

Unknown さんのコメント...

GetSettingFile()を関数化してましたけど、
Setting.xmlが変更になった時とかに保存するとこのコードだと上書きがおかしいですね。

保存の時はCreationCollisionOption.ReplaceExisting
とかを指定した方が良いですね。