我目前有这个TThread将一些图像下载到桌面,这是线程代码:
CheckComboBox
这里是调用Create Thread
的Formtype
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;
当应用程序Destroy我打电话:
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;
但是每次下载Thread Fired后关闭应用程序时都会出现运行时错误。这是因为我同时下载了多张图片吗?如果是这样有更好的方式来编写线程,如下载图像完成后等待,然后开始新的下载,如果这是真正的问题。
答案 0 :(得分:4)
在您发出终止线程的信号后,在之前调用{strong 1}} 释放它:
WaitFor()
此外,您的Form的逻辑可能同时运行多个下载线程,但您只跟踪创建的最后一个线程。只有在应用程序退出时,您才能在完成后释放它。您应该在每个线程上设置if Assigned(Downloadanimation) then
begin
Downloadanimation.Terminate;
Downloadanimation.WaitFor; // <-- add this
FreeAndNil(Downloadanimation);
end;
,或者将所有线程存储在FreeOnTerminate=True
中并使用他们的TList
事件来了解每个线程何时完成,以便您可以将其从列出并释放它。
另外,您的线程的OnTerminated
逻辑可以通过完全删除对Execute()
的调用来减少其网络流量,而是将TIdHTTP.Head()
属性设置为致电TIdHTTP.Request.Accept
时'image/gif'
。如果请求的资源存在但不是GIF,服务器应该报告TIdHTTP.Get()
响应,其他任何事件都会报告HTTP错误,就像406 Not Acceptable
会有的那样。在此示例中发送TIdHTTP.Head()
请求毫无意义。