FireMonkey の状態保存
FireMonkey の状態保存機能を利用すれば、アプリケーションの終了前の状態を記述したデータを保存することができます。状態保存データを使用して、アプリケーションの再起動後にその状態を回復することができます。
目次
状態保存機能がない場合のデバイスの動作
モバイル デバイス、特に Android プラットフォームでは、アプリケーションがバックグラウンドに移動すると、オペレーティング システムがそのアプリケーション プロセスの強制終了に踏み切る可能性があります。これは、メモリ不足のような特定の状況や単に実行中のプロセスが多すぎることなどに起因する場合があります。そのような場合、ユーザーが入力した情報はアプリケーションに残りません。
Android では、[設定|開発者向けオプション]内の[アクティビティを保持しない]オプションをオンにした場合、ホーム ボタンを押してからアプリケーションに戻るとアプリケーションが再起動するため、前に入力されたデータは失われます。
この問題を解決するため、Android には、"SaveState" と呼ばれる特別なストレージが用意されており、ここにアプリケーションの状態が保存され、アプリケーションの再起動時に返されます。この状態の保存は "一時的" なものにすぎません。つまり、アプリケーションを手動でまたはタスク マネージャから停止したあと再起動すると、それまでの "一時的な" 状態は失われます。
アプリケーションの再起動後に、アプリケーションがバックグラウンドに移動する前と同じ状態のままであれば便利なことがあります。
FireMonkey での状態保存機能
FireMonkey の状態保存機能を利用すれば、アプリケーションの終了前の状態を記述したデータを保存することができます。状態保存データを使用して、アプリケーションの再起動後にその状態を回復することができます。
状態保存の対象には、ユーザー データの他に、アクティブなタブ、編集コントロールに格納されているテキスト、チェック ボックスの選択状態、カレンダ日付、現在選択されている項目などの情報も含まれます。
FireMonkey の状態保存機能には、Android 固有の一時的な "SaveState" メカニズムにもディスクへのデータ保存による永続的な状態保存にも対処できるメカニズムが実装されています。Android 以外のプラットフォームでは、この機能は、ファイルを一時的な場所に保存することにより一時的な状態保存をエミュレートするほか、永続的な状態を希望する場所に格納します。
デスクトップ プラットフォームでのこの機能の動作は、モバイル プラットフォームでの動作と似ています。つまり、状態保存でアプリケーションの状態が保存されます。ストレージは必ず永続的であるとは限りません。たとえば、Windows では、この情報が保存されている一時ファイルを削除した場合、アプリケーションは初期状態から再起動し、終了前の状態に戻ることはありません。
このようなデータの保存を処理するため、TForm には OnSaveState イベントがあります。あらゆるフォーム データは、アプリケーションの再起動時に回復できるように、このイベントの発生時に保存されなければなりません。
TForm や TForm3D などの、TCommonCustomForm から派生した FireMonkey フォームには、状態保存の管理を目的とした TFormSaveState 型の SaveState プロパティがあります。TFormSaveState クラスでは、フォームの状態保存を管理するためのメソッドとプロパティを提供するほか、IFMXSaveStateService サービスを使用します。このサービスには、ターゲット プラットフォームでの状態保存の取得と設定に必要な機能が定義されています。
メモリ ストリーム
SaveState.Stream プロパティは、メモリ ストリームが TMemoryStream として格納される場所です。このプロパティにはいつでも読み書きできます。ただし、次の条件があります。
- Stream プロパティへのデータの書き込みは、OnSaveState イベントの発生時に行われるのが望ましい。
- Stream プロパティからのデータの読み取りは、OnCreate イベントの発生時に行われるのが望ましい。
このストリームを数値や文字列値などの情報の保存に役立つパラメータとして、TBinaryReader や TBinaryWriter などのヘルパ クラスを使用できます。
また、TCommonCustomForm からフォームを派生させずに、この機能にグローバルにアクセスすることもできます。プラットフォームに IFMXSaveStateService サービスを要求し、そのサービスのメソッドを使用して状態保存データの保存や読み込みを行うことができます。
ストレージの場所と名前
SaveState.StoragePath プロパティを使用すると、状態保存の "ストレージ パス" を次のように指定できます。
- StoragePath が空(デフォルト)であれば、状態保存は一時的であり、オペレーティング システムに用意されている機能(たとえば Android の "SaveState" など)か一時的な格納場所のどちらかを使用します。
モバイル プラットフォームでは、アクティビティがオペレーティング システムにより再起動される場合、データはそこにとどまりますが、アプリケーションがユーザーにより手動で強制終了される場合、データは失われます。他のプラットフォームでは、データは一時的な場所に保存され、これらの一時ファイルが削除される(たとえば Windows ではディスク クリーンアップの実行時など)までは引き続き使用可能です。
- StoragePath が空でない(たとえば TPath.GetHomePath に設定されるなどの)場合、状態保存は永続的であり、データはディスク上の指定の場所に保存されます。
状態保存データは実行中はそのままの状態にとどまり、SaveState.Stream.Clear を使ってこのデータを明示的にクリアするまでは、そこから情報を回復することができます。SaveState.Stream.Clear を使用するか、ブロック データ セットを nil にして IFMXSaveStateService.SetBlock を呼び出すことによりデータをクリアすると、データが一時ストレージから削除されます。永続ストレージ の場合は、ファイルが削除されます。
一時的状態の場合も永続的状態の場合も、SaveState.Name プロパティを希望する名前(ディスク上にある場合はファイル名)に設定することをお勧めします。Name プロパティを空のままにしておくと、アプリケーション名、クラス名、フォーム名を組み合わせてフォームが名前を生成します。
アプリケーションへの状態保存機能の追加
状態保存機能の使用法を説明するには:
- 新規のマルチデバイス アプリケーションを作成します。
- フォームに TEdit をドロップします。
- フォームを選択し、OnCreate イベントをダブルクリックして、次のコードを追加します。
Delphi の場合:
procedure TForm1.FormCreate(Sender: TObject); var R: TBinaryReader; begin if SaveState.Stream.Size > 0 then begin // 前に入力したテキストを Edit1 コントロールに回復する R := TBinaryReader.Create(SaveState.Stream); try Edit1.Text := R.ReadString; finally R.Free; end; end; end;
C++ の場合:void __fastcall TForm1::FormCreate(TObject *Sender) { TBinaryReader *R; if (SaveState->Stream->Size >0) { // 前に入力したテキストを Edit1 コントロールに回復する R = new TBinaryReader(SaveState->Stream, TEncoding::UTF8, false); try { Edit1->Text = R->ReadString(); } __finally { R->Free(); } } }
- フォーム デザイナに戻り、フォームを選択し、OnSaveState イベントをダブルクリックして、次のコードを追加します。
Delphi の場合:
procedure TForm1.FormSaveState(Sender: TObject); var W: TBinaryWriter; begin SaveState.Stream.Clear; // 何かが編集されたときにのみ現在の状態が保存される // 何も変更されていない場合は、状態がこのように削除される if Edit1.Text.Length > 0 then begin // 入力したテキストを Edit1 コントロールに保存する W := TBinaryWriter.Create(SaveState.Stream); try W.Write(Edit1.Text); finally W.Free; end; end; end;
C++ の場合:void __fastcall TForm1::FormSaveState(TObject *Sender) { TBinaryWriter *W; SaveState->Stream->Clear(); // 何かが編集されたときにのみ現在の状態が保存される // 何も変更されていない場合は、状態がこのように削除される if (Edit1->Text.Length() >0) { // 入力したテキストを Edit1 コントロールに保存する W = new TBinaryWriter(SaveState->Stream); try { W->Write(Edit1->Text); } __finally { W->Free(); } } }
上記のサンプル コードでは、保存データは一時的であり、たとえアプリケーションが再起動されても、Edit1 は自分のテキストを保持しています。この場合の状態保存は一時的なので、モバイル デバイスでは、アプリケーションが終了する(手動で停止される)と状態データは削除されます。
- この保存データを永続化するには、FormCreate イベントの冒頭に次のコード行を追加します。
Delphi の場合:
SaveState.StoragePath := TPath.GetHomePath;
- メモ: System.IOUtils を必ず uses 句に含めます。
C++ の場合:SaveState->StoragePath = System::Ioutils::TPath::GetHomePath();
- メモ: #include <System.IOUtils.hpp> を必ずヘッダー ファイルに含めます。
アプリケーションを Windows Vista 以降のプラットフォームで実行する場合は、~<アプリケーション名>_FM_<クラス名>_<フォーム名>.TMP という名前(たとえば ~SaveStateCodeSnippet_FM_TForm1_Form1.TMP など)の一時ファイルがホーム パス C:\Users\<ユーザー名>\AppData\Roaming に保存されます。