XE5 Android TBitmap.LoadFromStream在线程内失败

XE5 Android TBitmap.LoadFromStream在线程内失败,android,multithreading,delphi,delphi-xe5,Android,Multithreading,Delphi,Delphi Xe5,我正在使用DelphiXe5为Android创建一个简单的游戏。我有一些资源,PNG和JPEG,我想在我的程序加载所有资源时显示一个加载屏幕 但我发现将TBitmap.LoadFromFile或TBitmap.LoadFromStream代码放入android线程中会导致应用程序立即退出并返回到启动器,处于调试模式,Delphi甚至不会捕获异常。(该代码在Windows上运行完美,在Android上没有线程) 我必须打开logcat来查看发生了什么,我看到了类似“创建绘图上下文时出错”的内容 我

我正在使用DelphiXe5为Android创建一个简单的游戏。我有一些资源,PNG和JPEG,我想在我的程序加载所有资源时显示一个加载屏幕

但我发现将TBitmap.LoadFromFile或TBitmap.LoadFromStream代码放入android线程中会导致应用程序立即退出并返回到启动器,处于调试模式,Delphi甚至不会捕获异常。(该代码在Windows上运行完美,在Android上没有线程)

我必须打开logcat来查看发生了什么,我看到了类似“创建绘图上下文时出错”的内容

我的问题是,有没有一种方法可以使用Delphi XE5为Android制作加载屏幕?这样,当图像加载到内存中时,会显示一个进度屏幕


我创建测试项目只是为了隔离问题,下面是结果。LoadFromFile是线程1。日志显示线程实际运行了,但之后引发了异常

Logcat屏幕截图:
源代码:

经过大量测试和同事的帮助,我和同事解决了问题。解决方案不是终止线程并保持线程运行

我知道这有点奇怪。我试图关闭FreeOnTerminate,但它只控制线程对象,而不是实际的线程。似乎syncrhonized调用未进行syncrhonized。我不知道位图在何时何地被实际使用或复制。可能还有另一个GUI线程,因为Delphi编译的Android lib代码不会在主线程中运行

这是工作代码

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;

经过大量测试和同事的帮助,我和同事解决了这个问题。解决方案不是终止线程并保持线程运行

我知道这有点奇怪。我试图关闭FreeOnTerminate,但它只控制线程对象,而不是实际的线程。似乎syncrhonized调用未进行syncrhonized。我不知道位图在何时何地被实际使用或复制。可能还有另一个GUI线程,因为Delphi编译的Android lib代码不会在主线程中运行

这是工作代码

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;

这显然是一个应该在下一次更新中修复的bug。要对代码应用修复程序,请声明以下过程:

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;
并从System.Classes将其分配给EndThreadProc:

procedure TForm1.FormCreate(Sender: TObject);
begin
  EndThreadProc := MyEndThreadProc;
end;
使用此修复程序,您可以使用

FreeOnTerminate := true;
这样的代码就不会使应用程序崩溃了:

TYourThread.Create(something, somethingelse).Start;

我必须感谢Antonio Tortosa在Embarcadero论坛上发布了此解决方案。

这显然是一个bug,应该在下一次更新中修复。要对代码应用修复程序,请声明以下过程:

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;
并从System.Classes将其分配给EndThreadProc:

procedure TForm1.FormCreate(Sender: TObject);
begin
  EndThreadProc := MyEndThreadProc;
end;
使用此修复程序,您可以使用

FreeOnTerminate := true;
这样的代码就不会使应用程序崩溃了:

TYourThread.Create(something, somethingelse).Start;

我必须感谢Antonio Tortosa在Embarcadero论坛上发布了此解决方案。

位图来自何处?它是否与任何UI元素关联?不,线程中没有调用UI,我甚至创建了一个只有三行代码的测试项目。b:=TBitmap.Create;b、 LoadFromFile(TPath.Combine(TPath.GetDocumentPath+'koala.jpg');b、 免费的
TPath.Combine(TPath.GetDocumentPath+'koala.jpg')
应该是
TPath.Combine(TPath.GetDocumentPath,'koala.jpg')
。位图来自哪里?它是否与任何UI元素关联?不,线程中没有调用UI,我甚至创建了一个只有三行代码的测试项目。b:=TBitmap.Create;b、 LoadFromFile(TPath.Combine(TPath.GetDocumentPath+'koala.jpg');b、 免费的
TPath.Combine(TPath.GetDocumentPath+'koala.jpg')
应该是
TPath.Combine(TPath.GetDocumentPath,'koala.jpg')
。这不是解决方案。这将阻止线程终止。我也有同样的问题,我把我的答案贴在下面。同意上面的评论这不是一个解决办法。这将阻止线程终止。我也有同样的问题,我把我的答案贴在下面。同意上面的评论