gpt4 book ai didi

delphi - 如何在 TThread 中正确使用 Idhttp?

转载 作者:行者123 更新时间:2023-12-02 05:14:37 29 4
gpt4 key购买 nike

我目前有这个 TThread 将一些图像下载到桌面,这是线程代码:

type
TDownloadUpdateAnimateEvent = procedure(Sender: TObject; AAnimationname: String;
var AAnimationUrl: String) of object;

type
TDownloadanimation = class(TThread)
private
FOnUpdateAnimate: TDownloadUpdateAnimateEvent;
FAnimationname : String;
FAnimationUrl : string;
FPathImage : String;
ImageName: string;
PathURL: string;
FFileNameImage: string;
procedure DoUpdateAnimate;
protected
procedure Execute; override;
public
constructor Create(AAnimationname:string; AAnimationUrl: string; AOnUpdateAnimate : TDownloadUpdateAnimateEvent; APathImage : string);
property PathImage: string read FPathImage;
property FileNameImage: string read FFileNameImage;
end;

{ TDownloadanimation }

constructor TDownloadanimation.Create(AAnimationname, AAnimationUrl: string; AOnUpdateAnimate : TDownloadUpdateAnimateEvent; APathImage : string);
var
URI: TIdURI;
begin
inherited Create(false);
FOnUpdateAnimate := AOnUpdateAnimate;
FPathImage := APathImage;
FAnimationname := AAnimationname;
FAnimationUrl := AAnimationUrl;
URI := TIdURI.Create(FAnimationUrl);
try
ImageName := URI.Document;
PathURL := URI.path;
finally
FreeAndNil(URI);
end;
end;

procedure TDownloadanimation.DoUpdateAnimate;
begin
if Assigned(FOnUpdateAnimate) then
FOnUpdateAnimate(self, FAnimationname, FFileNameImage);
end;

procedure TDownloadanimation.Execute;
var
aMs: TMemoryStream;
aIdHttp: TIdHttp;
IdSSL: TIdSSLIOHandlerSocketOpenSSL;
path: string;
dir: string;
SPEXT : String;
itsimage: string;
responsechk: Integer;
begin
dir := AnsiReplaceText(PathURL, '/', '');

if (ImageName = '') then
begin
exit;
end;

path := PathImage + ImageName;

if fileexists(path) then
begin
FFileNameImage := path;
if Assigned(FOnUpdateAnimate) then
begin
Synchronize(DoUpdateAnimate);
end;
exit;
end
else
if not fileexists(path) then
begin
aMs := TMemoryStream.Create;
aIdHttp := TIdHttp.Create(nil);
IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
IdSSL.SSLOptions.Method := sslvTLSv1;
IdSSL.SSLOptions.Mode := sslmUnassigned;
aIdHttp.HTTPOptions := [hoForceEncodeParams] + [hoNoProtocolErrorException];
aIdHttp.IOHandler := IdSSL;
aIdHttp.AllowCookies := True;
aIdHttp.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';
aIdHttp.HandleRedirects := True;
aIdHttp.RedirectMaximum := 3;
try
aIdHttp.Head(trim(FAnimationUrl));
except
end;
itsimage := aIdHttp.Response.ContentType;
responsechk := aIdHttp.ResponseCode;

if responsechk <> 200 then
begin
FFileNameImage := 'error';
if Assigned(FOnUpdateAnimate) then
begin
Synchronize(DoUpdateAnimate);
end;
exit;
end;
if (itsimage = 'image/gif') then
begin
try
aIdHttp.Get(trim(FAnimationUrl), aMs);
except
end;
aMs.SaveToFile(path);
end;

try
if aIdHttp.Connected then
aIdHttp.Disconnect;
except
end;

finally
FreeAndNil(aMs);
FreeAndNil(IdSSl);
FreeAndNil(aIdHttp);
end;
end;

FFileNameImage := path;

if Assigned(FOnUpdateAnimate) then
begin
Synchronize(DoUpdateAnimate);
end;
end;

这是调用创建线程的表单

For i := 0 To imageslist.Count-1 do
begin
Animatref := 'ref';
Animaturl := imageslist.Strings[i];
URI := TIdURI.Create(Animaturl);
try
ImageName := URI.Document;
finally
FreeAndNil(URI);
end;

if (ExtractFileExt(ImageName) = '.gif') then
begin
if Fileexists(CheckPath+ImageName) then //if image exists then do something and dont start the Thread To download it
begin
//do something
end
else
if NOT Fileexists(CheckPath+ImageName) then // not found on desk and start to download
begin
addanimation(Animatref, Animaturl);
end;
end;
end;


procedure Tform1.addanimation(animationname, animationurl: string);
var
Pathanimate:string;
begin
Pathanimate := appfolder;
Downloadanimation := TDownloadanimation.Create(animationname, animationurl, UpdateAnimate, Pathanimate);
end;

当应用程序销毁时,我调用:

if Assigned(Downloadanimation) then
begin
Downloadanimation.Terminate;
FreeAndNil(Downloadanimation);
end;

但是每次下载 Thread Fired 后关闭应用程序时,我都会遇到运行时错误。这是因为我同时下载了多个图像吗?如果是这样,是否有更好的方法来编写线程,例如在下载图像完成后等待,然后开始新的下载(如果这是真正的问题)。

最佳答案

在向线程发出终止信号后,释放线程之前调用 WaitFor():

if Assigned(Downloadanimation) then
begin
Downloadanimation.Terminate;
Downloadanimation.WaitFor; // <-- add this
FreeAndNil(Downloadanimation);
end;

此外,您的表单逻辑有可能同时运行多个下载线程,但您只跟踪创建的最后一个线程。并且您不会在完成时释放它,只有在应用程序退出时才释放它。您应该在每个线程上设置 FreeOnTerminate=True,或者将所有线程存储在 TList 中,并使用它们的 OnTermminate 事件来了解何时每个线程都已完成,因此您可以将其从列表中删除并释放它。

另外一点,线程的 Execute() 逻辑可以通过完全删除对 TIdHTTP.Head() 的调用来减少其网络流量,而是设置调用 TIdHTTP.Get() 时将 TIdHTTP.Request.Accept 属性设置为 'image/gif'。如果请求的资源存在但不是 GIF,服务器应该报告 406 Not Acceptable 响应,其他任何资源都会报告 HTTP 错误,就像 TIdHTTP.Head 一样() 会有。在此示例中发送 HEAD 请求是没有意义的。

关于delphi - 如何在 TThread 中正确使用 Idhttp?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38861437/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com