Haifisch
Haifisch

Reputation: 909

Firemonkey external exception with thread and record on Android

With Firemonkey 10.4.2 (same with 10.4.1) I have a lot of error like the one below :

External exception 1 At address: $0000007FF99E60D0

Call stack: libMyApp.so $00000074942D3B64 Grijjy.Errorreporting.TgoExceptionReporter.GlobalGetExceptionStackInfo(TExceptionRecord*)

  • 124 libMyApp.so $0000007493A42480 Sysutils.Exception.RaisingException(TExceptionRecord*) + 52 libMyApp.so $0000007493A6D5B4 Sysutils.RaiseExceptObject(TExceptionRecord*) + 64 libMyApp.so $0000007493A227D0 _RaiseAtExcept(TObject*, Pointer) + 64 libMyApp.so $0000007493A4164C Internal.Excutils.SignalConverter(NativeUInt, NativeUInt, NativeUInt) + 36 libMyApp.so $00000074942CE0BC Pebble.Thread.TPebbleThread_Execute_ActRec._0_Body() + 1328 libMyApp.so $00000074942CE0BC Pebble.Thread.TPebbleThread_Execute_ActRec._0_Body() + 1328

To load marker on a MapView I use a thread create with FreeOnTerminate set to False.

TPebbleThread = class(TThread)
strict private
  FMapView: TMapView;
  FListMarker: TListCustomMapMarker;
  FLatitude: Double;
  FLongitude: Double;
  FShowMapViewAtEnd: boolean;
  FImgList: TImageList;
  FIsTerminate: boolean;
  FForceShowAllPebble: boolean;
  FCheckDuplicate: boolean;
public
  constructor Create(aMapView: TMapView; aListMarker: TListCustomMapMarker; aLatitude, aLongitude: Double);
  destructor Destroy; override;
  procedure Execute; override;
end;

This thread contain some property.

TListCustomMapMarker = class(TObjectList<TCustomMapMarker>)
  // ...
end

TCustomMapMarker = class
strict private
  FMarker: TMapMarker; // record in FMX.Maps
  FId: integer;
  FCreated: string;
  FAdded: string;
  FUser: string;
  FKm: string;
  FComment: string;
  FOwner: string;
  FFixed: boolean;
public
  constructor Create;
  destructor Destroy; override;
  // property
end;

I surrounded the execute method with a try..except. I saw some errors that I fixed, but these exception didn't go in my except.

It's like the exception is raise before all (may be when I call it a 2nd time ?)

On my main form, I load the map with my thread :

procedure TfrmMain.LoadMapMarker;
begin
  if Assigned(FPebbleThread) then
  begin
    FPebbleThread.Terminate;
  end;

  FListMarker.RemoveMapMarker;

  FPebbleThread := TPebbleThread.Create(FListMarker, ...);
end;

The full thread method is below :

procedure TPebbleThread.Execute;
var
  Url            : string;
  i              : integer;
  HTTPResponse   : TToolHTTPResponse;
  Value          : TJSONValue;
  Ar             : TJSONArray;
  LatitudeDouble : Double;
  LongitudeDouble: Double;
  Latitude       : string;
  Longitude      : string;
  CustomMapMarker: TCustomMapMarker;
  Id             : integer;
  Param          : TMultipartFormData;
begin
  inherited;
  FIsTerminate := False;
  try
    Param := TMultipartFormData.Create;
    try
      Param.AddField('latitude',  FLatitude.ToString);
      Param.AddField('longitude', FLongitude.ToString);

      Param.AddField('filter', 'on');

      HTTPResponse := TToolHTTP.Post(CST_URL_WS_GET_PEBBLE, Param);
    finally
      FreeAndNil(Param);
    end;

    if HTTPResponse.Valid then
    begin
      try
        Value := TJSONObject.ParseJSONValue(HTTPResponse.Content);
        Ar := Value.FindValue('item') as TJSONArray;

        try
          if Assigned(Ar) then
          begin
            try
              i := 0;

              while (i <= Ar.Count - 1) and not Terminated do
              begin
                Id := Ar.Items[i].GetValue<integer>('id');

                if not FCheckDuplicate or
                   (FCheckDuplicate and not FListMarker.Exists(Id)) then
                begin
                  Latitude  := Ar.Items[i].GetValue<string>('latitude');
                  Longitude := Ar.Items[i].GetValue<string>('longitude');

                  LatitudeDouble  := TToolMath.StrToFloat(Latitude);
                  LongitudeDouble := TToolMath.StrToFloat(Longitude);

                  if (LatitudeDouble <> 0) and (LongitudeDouble <> 0) then
                  begin
                    CustomMapMarker := TCustomMapMarker.Create;
                    CustomMapMarker.Id        := Id;

                    TThread.Synchronize(nil,
                    procedure
                    var
                      Descr: TMapMarkerDescriptor;
                    begin
                      if not Terminated then
                      begin
                        Descr := TMapMarkerDescriptor.Create(TMapCoordinate.Create(LatitudeDouble, LongitudeDouble), '');
                        Descr.Snippet := CustomMapMarker.Id.ToString;
                        Descr.Icon := FImgList.Bitmap(TSizeF.Create(CST_IMG_SIZE, CST_IMG_SIZE), CST_IMG_MARKER_FACEBOOK)

                        CustomMapMarker.Marker := FMapView.AddMarker(Descr);
                        FListMarker.Add(CustomMapMarker);
                      end;
                    end);
                  end;
                end;
                i := i + 1;
              end;
            except
              on E: Exception do
                raise Exception.Create('[On loading] ' + E.Message);
            end;
          end;
        finally
          FreeAndNil(Value);

          if FShowMapViewAtEnd then
          begin
            TThread.Synchronize(nil,
            procedure
            begin
              FMapView.Visible := True;
            end);
          end;
        end;
      except
        on E: Exception do
          raise Exception.Create('[loading] ' + E.Message);
      end;
    end;
  finally
    FIsTerminate := True;
  end;
end;

I spent a lot of time to see what can cause these error but that didn't work. Did you see a mistake somewhere ? thanks

Upvotes: 1

Views: 1564

Answers (1)

Vincent
Vincent

Reputation: 21

Ok, I would push a "FPebbleThread.WaitFor" in your frMain.LoadMapMarker, after the FPebbleThread.Terminate.

Such as this

if Assigned(FPebbleThread) then
begin
  FPebbleThread.Terminate;
  FPebbleThread.WaitFor;
end;

The TThread.Terminate method just set a boolean, your thread is certainly not propertly terminate when you create a new one.

Upvotes: 2

Related Questions