Firemonkey Application crash after multiple RESTRequests

  

Application

I’m developing a cross-platform app using Delphi where I need to constantly send RESTRequest’s to our server, but it is randomly crashing.

It’s an IOT app that reads sensors so I need to update the UI and it’s values at maximum speed.

Notes

First of all, I know the REST requests must be executed in a different thread, so it won’t block the UI and generate crashs.
The use of ExecuteAsync is strongly recommended for mobile apps, but using it actually crashes my application.
Using a TTimer would avoid the app from crashing, but the UI becomes very unresponsive and slow.
When I debug, the crash doesn’t happen at all.
I removed all UI updates to check and guarantee where the problem is.

Code

I’m currently using an AnonymousThread to perform the reads:

procedure TFormMain.ExecuteReadingThread(Sender: TObject);
begin
aReadingThread := TThread.CreateAnonymousThread(
procedure()
var
// JSON Data Response Array
json_data_response_object: TJSONObject;
json_data_response_array: TJSONArray;
begin
try
// Get REST data array from device
try
json_data_response_object := DM_KVA.GetDeviceData(communication_token, genset_id);
json_data_response_array := (json_data_response_object.GetValue(‘Device_Data’) as TJSONArray);
except
on E: Exception do
begin
// Free the Thread object in order to generate a Terminate event
TThread.CurrentThread.Free;
Exit;
end;
end;

if json_data_response_array <> nil then
begin
// Send UI Adjustments with a Thread-safe method
TThread.Synchronize(TThread.CurrentThread,
procedure()
begin
{
UI Updates
}
end);
end;

// Free the Thread object in order to generate a Terminate event
TThread.CurrentThread.Free;
except
on E: Exception do
begin
// Free the Thread object in order to generate a Terminate event
TThread.CurrentThread.Free;
Exit;
end;
end;
end);

// Threading Settings
aReadingThread.FreeOnTerminate := true;
aReadingThread.OnTerminate := TerminateRead;
aReadingThread.Start;
end;

And creating it again once it’s Terminated:

procedure TFormMain.TerminateRead(Sender: TObject);
begin
// Make Reading Thread execute again
ExecuteReadingThread(Sender);
end;

And this is how I execute the RESTRequest:

function TDM_KVA.GetDeviceData(ID_Token: string; ID_Device: string): TJSONObject;
var
JSObj: TJSONObject;
begin
// Set default RESTRequest parameters
RESTRequest_KVA.Resource := ‘api/v1/TServerMethods1’;
RESTRequest_KVA.Method := REST.Types.TRESTRequestMethod.rmGET;
RESTRequest_KVA.ResourceSuffix := Format(‘DeviceData/%s’, [ID_Device]);

try
// Execute command
RESTRequest_KVA.Timeout := 1;
RESTRequest_KVA.Execute;

except
on E: Exception do
begin
JSObj := nil;
Result := JSObj;
end;
end;

// Verify response
case (RESTResponse_KVA.StatusCode) of
200:
begin
// Successful readz
JSObj := (RESTRequest_KVA.Response.JSONValue as TJSONObject);
Result := JSObj;
end;
end;
end;

Question

What could I be missing? Is there a better way to implement multiple RESTRequests and keep it thread-safe?

Comments are closed.