XE5 Android TBitmap.LoadFromStream fail inside a thread

為{幸葍}努か 提交于 2019-12-19 11:43:04

问题


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:

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

回答1:


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.




回答2:


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;


来源:https://stackoverflow.com/questions/19364812/xe5-android-tbitmap-loadfromstream-fail-inside-a-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!