FTPサーバーからファイルをダウンロードするためにIdFTPを作成しましたが、スレッド化しようとすると、AndroidOSの「ホスト名を解決しています...」でスタックしました。
スレッドなし(正常に動作):
uses ..., IdFTPCommon;
var
RecordDownload: TMemoryStream;
uses System.IOUtils;
procedure TForm1.Button1Click(Sender: TObject);
begin
IdFTP1.Host := 'motoristaajudante.ddns.net';
IdFTP1.Port := 2121;
IdFTP1.DataPortMin := 50100;
IdFTP1.DataPortMax := 51100;
IdFTP1.Username := 'anonymous';
IdFTP1.TransferType := IdFTPCommon.TIdFTPTransferType.ftBinary;
IdFTP1.Passive := True;
try
IdFTP1.Connect();
IdFTP1.Get('00001.m4a',TPath.GetDocumentsPath + PathDelim + '00001.m4a',True,False);
except
IdFTP1.Disconnect;
end;
end;
procedure TForm1.IdFTP1AfterGet(ASender: TObject; AStream: TStream);
begin
IdFTP1.Disconnect;
end;
procedure TForm1.IdFTP1WorkEnd(ASender: TObject; AWorkMode: TWorkMode);
begin
if FileExists(TPath.GetDocumentsPath + PathDelim + '00001.m4a') then
begin
ShowMessage('Downloaded!');
end;
end;
そして、私がこのソリューションに従って作成したスレッドコード:
uses ..., IdFTPCommon;
type
TLoadThread = class(TThread)
public
constructor Create; reintroduce;
protected
procedure Execute; override;
end;
type
TForm1 = class(TForm)
...
procedure ThreadTerminated(Sender: TObject);
var
RecordDownload: TMemoryStream;
Loading: Boolean = False;
zLThread: TLoadThread = nil;
uses System.IOUtils;
constructor TLoadThread.Create;
begin
inherited Create(True);
FreeOnTerminate := True;
end;
procedure TLoadThread.Execute;
begin
try
Form1.IdFTP1.Connect();
Form1.IdFTP1.Get('00001.m4a',TPath.GetDocumentsPath + PathDelim + '00001.m4a',True,False);
except
Form1.IdFTP1.Disconnect;
end;
end;
procedure TForm1.ThreadTerminated(Sender: TObject);
begin
zLThread := nil;
Loading := False;
FloatAnimation1.Enabled := False;
FloatAnimation2.Enabled := False;
Arc3.StartAngle := -90;
Arc3.EndAngle := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
IdFTP1.Host := 'motoristaajudante.ddns.net';
IdFTP1.Port := 2121;
IdFTP1.DataPortMin := 50100;
IdFTP1.DataPortMax := 51100;
IdFTP1.Username := 'anonymous';
IdFTP1.TransferType := IdFTPCommon.TIdFTPTransferType.ftBinary;
IdFTP1.Passive := True;
zLThread := TLoadThread.Create;
zLThread.OnTerminate := ThreadTerminated;
zLThread.Start;
Loading := True;
FloatAnimation1.Enabled := True;
FloatAnimation2.Enabled := True;
end;
procedure TForm1.IdFTP1AfterGet(ASender: TObject; AStream: TStream);
begin
IdFTP1.Disconnect;
end;
procedure TForm1.IdFTP1WorkEnd(ASender: TObject; AWorkMode: TWorkMode);
begin
Form1.FloatAnimation1.Enabled := False;
Form1.FloatAnimation2.Enabled := False;
Form1.Arc3.StartAngle := -90;
Form1.Arc3.EndAngle := 0;
if FileExists(TPath.GetDocumentsPath + PathDelim + '00001.m4a') then
begin
ShowMessage('Downloaded!');
end;
end;
procedure TForm1.IdFTP1Status(ASender: TObject; const AStatus: TIdStatus;
const AStatusText: string);
begin
Memo1.Lines.Add(AStatusText);
Application.ProcessMessages;
end;
次に、FTPステータスは、「ホスト名を解決しています...」でスタックしていることを示します。正しくスレッド化するにはどうすればよいですか?
OnAfterGet
とOnWorkEnd
イベントを使用している方法で使用する理由はありません。インディは同期しています。TIdFTP.Get()
転送が終了するまで戻りません。エラーが発生すると、例外が発生します。
したがって、両方のイベントハンドラーを削除し、を呼び出すtry/finally
代わりにtry/except
を使用しDisconnect()
、発生Get()
しない場合にのみダウンロードを処理します。
OnWorkEnd
そしてOnStatus
イベントは、呼び出した同じスレッドのコンテキストでトリガされConnect()
、Disconnect()
とGet()
。したがって、スレッド化された例では、それはメインスレッドではなく、ワーカースレッドになります。ただし、イベントハンドラーはUIコントロールへのアクセスを同期していません。それはあなたが経験しているフリーズを含むあらゆる種類の問題を引き起こす可能性があります。同期する必要があります(TThread.OnTerminated
イベントは同期されます)。
そうは言っても、代わりにこれを試してください:
非スレッド:
uses
..., IdFTPCommon;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
IdFTP1.Host := 'motoristaajudante.ddns.net';
IdFTP1.Port := 2121;
IdFTP1.DataPortMin := 50100;
IdFTP1.DataPortMax := 51100;
IdFTP1.Username := 'anonymous';
IdFTP1.TransferType := IdFTPCommon.TIdFTPTransferType.ftBinary;
IdFTP1.Passive := True;
try
IdFTP1.Connect;
try
IdFTP1.Get('00001.m4a', TPath.GetDocumentsPath + PathDelim + '00001.m4a', True, False);
finally
IdFTP1.Disconnect;
end;
ShowMessage('Downloaded!');
except
ShowMessage('Error while downloading!');
end;
end;
スレッド:
uses
..., IdFTPCommon;
type
TLoadThread = class(TThread)
public
constructor Create; reintroduce;
protected
procedure Execute; override;
end;
type
TForm1 = class(TForm)
...
IdFTP1: TIdFTP;
procedure ThreadTerminated(Sender: TObject);
...
private
Loading: Boolean;
zLThread: TLoadThread;
end;
...
constructor TLoadThread.Create;
begin
inherited Create(True);
FreeOnTerminate := True;
end;
procedure TLoadThread.Execute;
begin
Form1.IdFTP1.Connect;
try
Form1.IdFTP1.Get('00001.m4a', TPath.GetDocumentsPath + PathDelim + '00001.m4a', True, False);
finally
Form1.IdFTP1.Disconnect;
end;
end;
procedure TForm1.ThreadTerminated(Sender: TObject);
begin
zLThread := nil;
Loading := False;
FloatAnimation1.Enabled := False;
FloatAnimation2.Enabled := False;
Arc3.StartAngle := -90;
Arc3.EndAngle := 0;
If TThread(Sender).FatalException = nil then
ShowMessage('Downloaded!')
else
ShowMessage('Error while Downloading!');
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
IdFTP1.Host := 'motoristaajudante.ddns.net';
IdFTP1.Port := 2121;
IdFTP1.DataPortMin := 50100;
IdFTP1.DataPortMax := 51100;
IdFTP1.Username := 'anonymous';
IdFTP1.TransferType := IdFTPCommon.TIdFTPTransferType.ftBinary;
IdFTP1.Passive := True;
zLThread := TLoadThread.Create;
zLThread.OnTerminate := ThreadTerminated;
zLThread.Start;
Loading := True;
FloatAnimation1.Enabled := True;
FloatAnimation2.Enabled := True;
end;
procedure TForm1.IdFTP1Status(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string);
begin
TThread.Queue(nil,
procedure
begin
Memo1.Lines.Add(AStatusText);
end
);
end;
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加