Hallo,
ich habe mal eine Frage wie ihr folgendes Problem lösen würdet. Bei einem Projekt lade ich diverse Grafiken von einem Server zeige diese in einer Grid an. Damit das UI keinen Herzinfarkt bekommt, lade ich die Bilder im Hintergrund. Mein Code ist folgender:
Delphi-Quellcode:
function GetHtml(const AUri: String; Stream: TStream): Boolean;
var
{$IFDEF USEINDY}
http: TidHttp;
{$ELSE}
http: THttpClient;
{$ENDIF}
begin
Result := false;
http := {$IFDEF USEINDY} TidHttp.Create(nil) {$ELSE} THttpClient.Create
{$ENDIF};
try
try
http.Get(AUri, Stream);
Result := true;
Stream.Position := 0;
except
end;
finally
http.DisPoseOf;
end;
end;
procedure RetrieveImage(ALogo: String; const AZip: TZipFile;
const AOnAvailable: TOnStreamAvailable; const ACached: Boolean);
begin
if assigned(AOnAvailable) then
RetrieveImage(ALogo, AZip,
procedure(const AStream: TStream)
begin
AOnAvailable(AStream);
end, ACached);
end;
procedure RetrieveImage(ALogo: String; const AZip: TZipFile;
const AOnAvailable: TOnStreamAvailableDirect; const ACached: Boolean);
var
Stream: TStream;
LocalHeader: TZipHeader;
begin
if not assigned(AOnAvailable) then
exit;
if (Pos('://', ALogo) = 0) and FileExists(ALogo) then
begin
Stream := TMemoryStream.Create;
try
TMemoryStream(Stream).LoadFromFile(ALogo);
except
end;
AOnAvailable(Stream);
Stream.DisPoseOf;
end
else if assigned(AZip) and (Pos('zip://', ALogo) > 0) then
begin
ALogo := StringReplace(ALogo, 'zip://', '', [rfReplaceAll]);
if AZip.IndexOf(ALogo) > -1 then
begin
FLock.Enter;
AZip.Read(ALogo, Stream, LocalHeader);
FLock.Leave;
AOnAvailable(Stream);
Stream.DisPoseOf;
end;
end
else if (Pos('http://', ALogo) > 0) or (Pos('https://', ALogo) > 0) then
begin
TTask.Run(
procedure()
var
Stream: TMemoryStream;
Filename: String;
begin
Filename := TPath.Combine(TPath.GetTempPath, IntToStr(Crc32(ALogo)) +
ExtractFileExt(ALogo));
Stream := TMemoryStream.Create;
if (ACached) and FileExists(Filename) then
try
Stream.LoadFromFile(Filename)
except
end
else if GetHtml(ALogo, Stream) and ACached then
try
Stream.SaveToFile(Filename);
except
end;
Stream.Position := 0;
TThread.Queue(nil,
procedure()
begin
if assigned(AOnAvailable) then
AOnAvailable(Stream);
Stream.Free;
end);
end).Start;
end;
end;
Ich bin nicht richtig glücklich damit, da unter Umständen ein Bild doppelt geladen werden kann und ich im schlimmsten Fall das Bild speichere und gleichzeitig in einem anderen Thread schon lade. Man müsste das jetzt absichern. Mein Ansatz wäre eine CriticalSection beim speichern und laden zu verwenden und in einem Dictionary
Url und Dateiname zu hinterlegen. Kennt jemand eventuell eine elegantere Variante?
Das zweite Problem sind defekte Downloads. Ich kriege die ja nicht mit und ab und wenn man jetzt ein kaputtes Bild einem TBitmap.CreateFromStream oder LoadFromStream übergibt, gibts eine
Exception. Nach einiger Zeit hilft aber kein try except end und die Anwendung wird klaglos beendet. Zumindest auf Android. Schaut man dann in die Konsole steht meist irgendwas mit
OpenGL fatal irgendwas als Grund für das Schließen der App. Ich hab absolut keine Ahnung inwieweit ich die Validität der geladenen Bilder überprüfe und bei offensichtlichem Unsinn ignoriere.
Das dritte Problem ist wie und wann lösche ich den temporären Pfad? Muss ich dass überhaupt, oder säubert das Android bzw. IOS von alleine?
Peter