红鱼儿

Delphi10.2.3利用THttpClient实现http异步下载

随着Delphi 10.2.3的发布,随之带来更稳定、更完善的版本。今天借官方的例子,解读一下如何实现Http异步下载并显示下载进度。

使用的核心组件是THttpClient,首先建立一个THttpClient对象FClient,用他来执行下载任务。
procedure TFormDownloadDemo.FormCreate(Sender: TObject);
begin
  FClient := THTTPClient.Create;
  FClient.OnReceiveData := ReceiveDataEvent;
end;

我们看到,这里为FClient实现了OnReceiveData事件,目的用来显示下载进度,注意这个事件在异步执行Http下载时,是在线程中执行的。来看一下具体的实现代码:

procedure TFormDownloadDemo.ReceiveDataEvent(const Sender: TObject; AContentLength, AReadCount: Int64;
  var Abort: Boolean);
var
  LTime: Cardinal;
  LSpeed: Integer;
begin
  LTime := TThread.GetTickCount - FGlobalStart;//计算用时
  LSpeed := (AReadCount * 1000) div LTime;//计算下载速度
  TThread.Queue(nil,
    procedure
    begin
      ProgressBarDownload.Value := AReadCount;//显示下载进度
      LabelGlobalSpeed.Text := Format('Global speed: %d KB/s', [LSpeed div 1024]);//显示下载速度
    end);
end;
AContentLength:下载内容的长度
AReadCount:已经下载的字节数
在这个事件中,计算每秒下载字节数,并用ProgressBarDownload可视组件来显示进度。
因为这个事件在线程中执行,所以同步界面上的ProgressBarDownload进度条时,用了TThread.Queue同步主线程。
 
接下来,实现具体的下载方法,并用一个按钮来执行这个方法,执行下载任务:
procedure TFormDownloadDemo.SampleDownload;
var
  URL: string;
  LResponse: IHTTPResponse;
  LFileName: string;
  LSize: Int64;
begin
  LFileName := TPath.Combine(TPath.GetDocumentsPath, EditFileName.Text);//本地保存的文件地址
  try
    URL := EditURL.Text;//文件的URL地址
    
    LResponse := FClient.Head(URL);//取得IHTTPResponse接口,通过该接口获得下载文件的长度
    LSize := LResponse.ContentLength;//求出下载内容的长度
    Memo1.Lines.Add(Format('Head response: %d - %s', [LResponse.StatusCode, LResponse.StatusText]));
    LResponse := nil;

    ProgressBarDownload.Max := LSize;//设置进度条的最大值
    ProgressBarDownload.Min := 0;
    ProgressBarDownload.Value := 0;
    LabelGlobalSpeed.Text := 'Global speed: 0 KB/s';

    Memo1.Lines.Add(Format('Downloading: "%s" (%d Bytes) into "%s"' , [EditFileName.Text, LSize, LFileName]));

    // 建立一个文件流FDownloadStream,准备用于保存下载内容
    FDownloadStream := TFileStream.Create(LFileName, fmCreate);//建立下载文件流
    FDownloadStream.Position := 0;

    FGlobalStart := TThread.GetTickCount;//取开始下载时间,用于计算下载速度

    // 开始下载
    FAsyncResult := FClient.BeginGet(DoEndDownload, URL, FDownloadStream);

  finally
    BStopDownload.Enabled := FAsyncResult <> nil;//下载过程中允许中止下载
    BStartDownload.Enabled := FAsyncResult = nil;//下载完成后允许开始下载
  end;
end;
上面对下载方法进行了注释,但还有必要说一下这个具体的下载调用所要实现的目的:
 
FAsyncResult := FClient.BeginGet(DoEndDownload, URL, FDownloadStream);
 
我们看到,用FClient.BeginGet执行下载,同时传进去三个参数:
DoEndDownload:一个方法,下载完成后调用
URL:下载内容的URL
FDownLoadStream:保存下载内容的文件流。
 
重点在于DoEndDownload方法的实现:
procedure TFormDownloadDemo.DoEndDownload(const AsyncResult: IAsyncResult);
var
  LAsyncResponse: IHTTPResponse;
begin
  try
    LAsyncResponse := THTTPClient.EndAsyncHTTP(AsyncResult);//通过传进来的参数,取得异步响应接口
    TThread.Synchronize(nil,
      procedure
      begin
        Memo1.Lines.Add('Download Finished!');
        Memo1.Lines.Add(Format('Status: %d - %s', [LAsyncResponse.StatusCode, LAsyncResponse.StatusText]));
      end);
  finally
    LAsyncResponse := nil;
    FreeandNil(FDownloadStream);
    BStopDownload.Enabled := False;
    BStartDownload.Enabled := True;
  end;
end;
首先这个方法,要声明成下面这样:
procedure (const ASyncResult: IAsyncResult);
然后我们看到,在具体的实现中,使用了传进来的参数ASyncResult,取得下载后接口LAsyncResponse,并通过该接口,进一步取得下载后的信息。
然后做的第二件事是释放保存下载的文件流FDownloadStream,最后设置开始下载按与中止下载按钮的状态。
同样,我们也看到,这里使用了TThread.Synchronize来同步界面,那说明这个方法也是在线程中执行的。
 
好了,在线程中下载文件并在界面上显示下载进度的整个过程基本就说完了。具体的例子代码在
C:\Users\Public\Documents\Embarcadero\Studio\19.0\Samples\Object Pascal\RTL\HttpAsyncDownload
这个例子是哪一个版本支持的,我也记不清,反正今天看到,全当10.2.3带的好了,其实这已不重要,重要的是,参考他来实现自己的http异步下载!
 
众所周知,这是一个跨平台的版本,同样的实现,可同时用于Android,IOS,Windows,OSX,Linux...这才是真正让人兴奋的事情。现在,我要集成到我的项目中去了...
 

posted on 2019-07-18 11:43  红鱼儿  阅读(2454)  评论(0编辑  收藏  举报