简体   繁体   中英

XE5 Android TBitmap.LoadFromStream fail inside a thread

I am creating a simple game for Android using Delphi XE5. I have a few resources, PNGs and Jpegs, I wanted to show a loading screen while my program loads up all the resources.

But I found putting TBitmap.LoadFromFile, or TBitmap.LoadFromStream code inside a android thread, caused the App to quit immediately and return to Launcher, in debug mode Delphi don't even catch an exception. (The code works perfectly on Windows, and without thread on Android)

I had to open logcat to see what went on, I saw something like "Error creating drawing context".

My question is there a way to make a loading screen for Android using Delphi XE5? So that a progress screen shows while images gets loaded in memory.


I created test project just to isolate the problem, here are the result. LoadFromFile is Thread 1. The log suggests thread actually ran, but Exceptions were raised afterwards???

Logcat screenshot: Logcat结果 Source code: http://www.pockhero.com/wp-content/uploads/2013/10/threadtest1.7z

This apparently is a bug that is supposed to be fixed in the next update. To apply the fix to your code, declare this procedure:

uses
  Androidapi.NativeActivity,
  Posix.Pthread;


procedure MyEndThreadProc(ExitCode:Integer);
var
  PActivity: PANativeActivity;
begin
    PActivity := PANativeActivity(System.DelphiActivity);
    PActivity^.vm^.DetachCurrentThread(PActivity^.vm);
    pthread_exit(ExitCode);
end;

and assign it to the EndThreadProc from System.Classes:

procedure TForm1.FormCreate(Sender: TObject);
begin
  EndThreadProc := MyEndThreadProc;
end;

With this fix you can set, for example, your thread with

FreeOnTerminate := true;

and then a code like this won't crash the application anymore:

TYourThread.Create(something, somethingelse).Start;

I have to give credit to Antonio Tortosa for posting this solution in Embarcadero forums.

After a lots of testing and colleague's help, my colleague and I solved the problem. The solution is not to terminate the thread and keep the thread running.

I know this is a bit odd. I tried to turn FreeOnTerminate off, but it only control the thread object, not the actually thread. It appears as if syncrhonized call is not syncrhonized. I have no idea when and where the bitmap is actually being used or copied. Possiblly there is another GUI thread somewhere, since Delphi compiled Android lib code don't run in the main thread anyway.

Here is working code.

procedure TBitmapThread.Execute;
begin
  inherited;
  BeforeExecute;
  try
    fBitmap := TBitmap.CreateFromFile(TPath.Combine(TPath.GetDocumentsPath, 'koala.jpg'));
    // Sleep(2000);
    Synchronize(UpdateImage);
    // Keep the thread running
    while not Terminated do
    begin
      Sleep(100);
    end;
    fBitmap.Free;
  except
    on E:Exception do
    begin
      Log.d('TestThread Exception: ' + E.message);
    end;
  end;
  AfterExecute;
end;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM