Einzelnen Beitrag anzeigen

AndyDF

Registriert seit: 6. Sep 2006
Ort: Allgäu
99 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Android App hängt bei Neustart

  Alt 4. Mär 2016, 11:47
Nach einigen schlaflosen Nächten und viel Tests konnte ich das Problem jetzt reduzieren.
Es hat gar nichts mit der GUI zu tun sondern irgendwie mit TBitmap Objekten (unter Firemonkey).

Mein Ablauf, um ein Bild in die GUI zu bekommen:

1. In einem Hintergrund Thread wird ein Bild geladen (aus der DB). Dann habe ich ein TArray<Byte>
2. Durch TThread.Queue(...) wird dieses Byte-Array in den Haupt-Thread gebracht
3. Aus dem Byte-Array wird ein TBitmap erzeugt, welches dann in der GUI angezeigt wird.

Klappt auch alles wunderbar! Nur lade ich auf diesem Wege einige Bilder hintereinander so dass der Vorgang schon mal ein paar Sekunden dauert.
Lege ich die App während (!) des Ladens in den Hintergrund und hole sie wieder in den Vordergrund so bleibt sie hängen!

Passiert aber nur bei Android!
In meinem Fall: Nexus 5, Android v5.1.1 (hatte aber bis gestern irgend eine 4er Version drauf, auf der ging es auch nicht. Glaube v4.4.x).

Im Folgenden habe ich ein Beispiel (komplette Unit). Dieses Beispiel demonstriert den oberen Ablauf, wie er ungefähr bei mir aussieht.
Das Beispiel ist natürlich sinnfrei - aber halt auf den Fehler reduziert.

Wird in der Methode "ProcessBitmap" die Zeile "Bitmap.LoadFromStream(MS);" aus kommentiert funktioniert es und die App bleibt nicht hängen.
Hängt irgendwie mit den internen Aktionen von TBitmap zusammen. Aber ich bin doch schon im Haupt-Thread!


Habe ich da was vom Ablauf falsch gemacht oder ist es tatsächlich ein Bug??

Mein Code:

Code:
unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.ListView.Types, FMX.ListView.Appearances,
  FMX.ListView.Adapters.Base, FMX.ListView, FMX.Controls.Presentation, FMX.StdCtrls, System.Threading, FMX.Objects;

type
  TBinaryData = TArray<Byte>;

  TFrmMain = class(TForm)
    Button1: TButton;
    imgAlbert: TImage;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    FTask: ITask;
    FData: TBinaryData;
    procedure ProcessBitmap(const AData: TBinaryData);
  end;

var
  FrmMain: TFrmMain;

implementation


{$R *.fmx}

procedure TFrmMain.FormCreate(Sender: TObject);
var
  MS: TMemoryStream;
begin
  MS := TMemoryStream.Create;
  try
    //Bild nur dummy in der Form, so dass die Daten in ein Byte-Array geladen werden können

    imgAlbert.Bitmap.SaveToStream(MS);
    MS.Position := 0;

    SetLength(FData,MS.Size);
    MS.Read(FData[0],MS.Size);

  finally
    MS.DisposeOf;
    MS := nil;
  end;
end;

procedure TFrmMain.Button1Click(Sender: TObject);
begin
  if Assigned(FTask) then
  begin
    FTask.Cancel;
    FTask := nil;
    Button1.Text := 'Start Task';
  end else
  begin
    FTask := TTask.Run(procedure
      var
        CopyOfData: TBinaryData;
      begin
        while true do
        begin
          CopyOfData := Copy(FData); //FData muss natürlich abgesichert werden - passt aber für Beispiel. Ist ja nur ein Thread.

          TThread.Queue(nil,procedure
            begin
              ProcessBitmap(CopyOfData);
            end);
          Sleep(100);
        end;
      end);
    Button1.Text := 'Stop Task';
  end;
end;

procedure TFrmMain.ProcessBitmap(const AData: TBinaryData);
var
  Bitmap: TBitmap;
  MS: TMemoryStream;
begin
  Bitmap := TBitmap.Create;
  MS := TMemoryStream.Create;
  try
    MS.Position := 0;
    MS.Write(AData[0],Length(AData));
    MS.Position := 0;

    { !!!!! Mit dieser Zeile: FEHlER ! - sonst läuft es !!!! }
    Bitmap.LoadFromStream(MS);

    //jetzt normalerweise Bild in der GUI anzeigen... ist aber nicht die Fehlerursache

  finally
    MS.DisposeOf;
    MS := nil;

    Bitmap.DisposeOf;
    Bitmap := nil;
  end;
end;


end.
Info: Im imgAlbert ist irgend ein Bild geladen! In diesem Fall eines von Albert Einstein. Aber das sollte ja nicht die Fehlerursache sein.
Andreas Blenk
  Mit Zitat antworten Zitat