Using SaveState service in Delphi apps

In Delphi FMX, it is possible to save and retrieve data form the last state of your app.

This mean that, when your app is closed (on Windows and macOS) or moved to the background (on Android), its state’s data such as form’s properties, controls’s inputs and values can be stored to a temporar or permanent stream storage. Then, on the next form creation, these data are loaded and used again.

Let’s see how it can work through this quick tutorial :

Saving data

To save data, you have to call the SaveState object using your form’s OnSaveState event handler. And follow these steps :

  • Declare a variable of TBinaryWriter.
  • Set a path to be used by SaveState.StoragePath property.
  • Clear the SaveState’s stream.
  • Create an instance of TBinaryWriter using the SaveState’s stream.
  • Now, using the instruction (try … finally … end;), save your data (control’s values) using the writing procedures, then release the TBinaryWriter’s instance.
procedure TMainForm.FormSaveState(Sender: TObject);
var
W : TBinaryWriter;

begin
SaveState.StoragePath := CrossPath.GetConfigPath;
SaveState.Stream.Clear;
W := TBinaryWriter.Create(SaveState.Stream);
  try
  W.Write(Switch1.IsChecked);  
  W.Write(ComboBox1.ItemIndex); 
  W.Write(Edit1.Text);   
  finally    
  W.Free;   
  end;

end;

Loading data

To load the saved data, you have to call the SaveState object using your form’s creation event handler. And you have to follow these steps :

  • Declare a variable of TBinaryReader.
  • Set the path to your saved data in the SaveState.StoragePath property.
  • Start a condition to check if the SaveState’s stream is not empty. Then :
    • Create an instance of TBinaryReader using the SaveState’s stream.
    • Now, using the instruction (try … finally … end;), load your data (control’s values) using the reading procedures, then release the TBinaryReader’s instance.
  • In addition, if the SaveState’s stream is empty (data not found, file removed or memory cleared), then you can set a second action to create controls with a default values.
procedure TMainForm.FormCreate(Sender: TObject);
var  
R : TBinaryReader;
begin
SaveState.StoragePath := CrossPath.GetConfigPath;
if SaveState.Stream.Size > 0
then   
  begin
  R := TBinaryReader.Create(SaveState.Stream);
    try
    Switch1.IsChecked := R.ReadBoolean;
    ComboBox1.ItemIndex := R.ReadInteger;
    Edit1.Text := R.ReadString;
    finally
    R.Free;
    end;   
  end

else
//If no saved data found
Edit1.Text := 'Hello again';
end;

Writing a complex code

It is possible to implement the whole saving and loading parts of your code in a separates procedures to be called with events handlers. Like the following example for saving data using a procedure to be called in the FormSaveState event :

procedure TMainForm.SaveSettings;
var
W : TBinaryWriter;

begin
SaveState.StoragePath := CrossPath.GetConfigPath;
SaveState.Stream.Clear;
W := TBinaryWriter.Create(SaveState.Stream);
  try
  W.Write(Switch1.IsChecked);  
  W.Write(ComboBox1.ItemIndex); 
  W.Write(Edit1.Text);   
  finally    
  W.Free;   
  end;
end;


procedure TMainForm.FormSaveState(Sender: TObject);
begin
SaveSettings;
end;

There is also an option to load data, use a function that return boolean value :

  • If the SaveState’s stream is not empty, then it return “True” and it load your data.
  • Else, the function will return “False”, and you can use this response to create the form’s controls with default values.

function TMainForm.LoadSettings : Boolean;
var  
R : TBinaryReader;
begin
SaveState.StoragePath := CrossPath.GetConfigPath;
if SaveState.Stream.Size > 0
then   
  begin
  R := TBinaryReader.Create(SaveState.Stream);
    try
    Switch1.IsChecked := R.ReadBoolean;
    ComboBox1.ItemIndex := R.ReadInteger;
    Edit1.Text := R.ReadString;
    finally
    R.Free;
    end;   
  Result := True;  
  end

else
//If no saved data found
Result := False; 
end;


procedure TMainForm.FormCreate(Sender: TObject);
begin
if LoadSettings = False then
//Create the form's controls with default values
Edit1.Text := 'Hello again';
end;

See also

Leave a Reply