Search code examples
androidrestdelphicrashfiremonkey

Delphi Android RESTRequest: channel is unrecoverably broken and will be disposed


After several times running RESTRequest.Execute without any errors, my Android application crashes randomly.

Although I'm developing with Firemonkey, I could only get to the error by checking it at Android Studio's DDMS logcat.

535-614/? E/InputDispatcher﹕ channel '221d0340 com.mycompany.myappname/com.embarcadero.firemonkey.FMXNativeActivity (server)' ~ Channel is unrecoverably broken and will be disposed!

I found out that it usually indicates a Memory Leak in the application, however I'm clueless on how to prevent it from happening.

  • Debugging at Delphi shows no crashes at all.

This is how I call the RESTRequests on the main Form:

procedure TFormMain.ExecuteReadingThread(Sender: TObject);
begin

    aReadingThread := TThread.CreateAnonymousThread(
        procedure()
        begin

            try
                json_data_response_object := DM_KVA.GetDeviceData(communication_token, genset_id);
            except
                on E: Exception do
                begin
                    // Ignore
                end;
            end;

            TThread.Queue(aReadingThread,
            procedure()
            begin

            // Send UI Adjustments with a Thread-safe method

            end);


        end);

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

end;

procedure TFormMain.TerminateRead(Sender: TObject);
begin

        // Make Reading Thread take it's place
        ExecuteReadingThread(Sender);

end;

And this is how it's executed on the DataModule:

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.Execute;

    except
        on E: EIdHTTPProtocolException do
        begin
            // Ignore
        end;
        on E: TRESTResponse.EJSONValueError do
        begin
            // Ignore
        end;
        on E: EIdUnknownProtocol do
        begin
            // Ignore
        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;

How can I avoid these random Memory Leaks from crashing my Android application?


Solution

  • As the code is written, it seems as the scope of json_data_response_object is wider than ExecuteReadingThread.

    Under ARC memory model an object is automatically disposed of when it goes out of scope. But here it does not go out of scope between calls to ExecuteReadingThread. Instead the pointer to the object is constantly overwritten until there are no memory left (lots of leaks).

    How can I avoid these random Memory Leaks from crashing my Android application?

    There is no point in having a wide scope of the json_data_response_object, since accessing it outside the anonymous thread is dangerous (it is ok in the OnTerminate event handler though). I would recommend to declare the object inside the anonymous thread. Likewise the aReadingThread is better declared inside ExecuteReadingThread to avoid confusion.


    One final point: Set the Result variable of GetDeviceData to nil at the beginning of the method to guarantee that a valid value is assigned in all circumstances.