与FireMonkey并行的多个REST请求

Emu*_*lic 8 delphi rest multithreading asynchronous

我正在Rad Studio XE7中构建一个Firemonkey应用程序,只需单击一下按钮,我就需要使用TRestRequest进行多次(大约7次)Web服务调用.每个Web服务都将返回json对象,然后填充数据集.我正在寻找一种同时进行这些调用的方法,而不是要锁定应用程序的UI.

您建议以哪种方式执行此操作?我看到Embarcadero为线程引入了新的任务和功能,但我仍然不确定我们是否可以使用它以及如何使用.另外,我看到有一个函数可以异步执行TRestRequest,使用这个函数:

function TCustomRESTRequest.ExecuteAsync(ACompletionHandler: TCompletionHandler = nil; ASynchronized: boolean = true; AFreeThread: boolean = true): TRESTExecutionThread;
Run Code Online (Sandbox Code Playgroud)

但我找不到任何关于如何使用此方法及其作用的文档.

任何输入将不胜感激.

S.L*_*ica 2

方法ExecuteAsync(ACompletionHandler: TCompletionHandler = nil; ASynchronized: boolean = true; AFreeThread: boolean = true)确实是要走的路。顾名思义,它是异步的;这意味着您的程序在触发请求后,甚至在触发多个请求后仍保持响应。
然而,重要的是从不同的对象实例激发这些不同的请求;ExecuteAsync如果您从TRESTRequest已经执行 的实例中触发ExecuteAsync,则新请求将妨碍现有请求。TRESTRequest您必须为每个并行调用创建一个单独的实例。

注意它的第一个参数是一个过程;您将您选择的过程作为该参数传递。唯一的要求是该过程有正确的签名;在这种情况下,它是一个没有参数的过程。

ExecuteAsync 方法在 中定义REST.Client。(我有 Delphi XE-10.1。Berlin,所以它有一个额外的参数,ACompletionHandlerWithError- 出错时调用。但原理保持不变)。

我们来看一下:

function TCustomRESTRequest.ExecuteAsync(ACompletionHandler: TCompletionHandler = nil; ASynchronized: boolean = true;
  AFreeThread: boolean = true; ACompletionHandlerWithError: TCompletionHandlerWithError = nil): TRESTExecutionThread;
begin
  Result := TRESTExecutionThread.Create(Execute, self, ACompletionHandler, ASynchronized, AFreeThread, ACompletionHandlerWithError);
end;
Run Code Online (Sandbox Code Playgroud)

这里发生的是创建一个新线程,在其中执行 REST 请求。如果有响应,则由 处理ACompletionHandler
默认情况下,ACompletionHandler在由 . 创建的新线程上运行ExecuteAsync。如果你想让它在主线程上运行,你应该设置ASynchronizedtrue

但如何才能访问该响应,并使其可供程序的其余部分访问呢?

FireMonkey 的 TRESTRequest 类有一个属性Response,它引用包含服务器对我们的请求的响应的 TRESTResponse 对象。
不幸的是,TRESTRequest 和 TRESTResponse 对象都没有传递给我们的 CompletionHandler!

因此我们需要以某种方式向 CompletionHandler 提供此信息。幸运的是,我们可以使用一个方法作为 CompletionHandler。

我们假设要处理结果数据的类称为DataOwner。我们的目的是DataOwner访问与我们的 TRESTRequest 实例关联的 TRESTResponse 实例。
最简单的方法是使 TRESTRequest 和/或 TRESTResponse 成为以下成员DataOwner

MyRESTRequest假设您的请求是从由函数命名和处理的 TRESTRequest 实例触发的processResponse,您将使用以下代码:

type TDataOwner = class
   MyData: TSomeDataType;
   procedure GetData();
   procedure FillDataSet();
end;

implementation

procedure DataOwner.GetData();
begin
  // ... initialize MyRESTRequest here...
  MyRESTRequest.ExecuteAsync(FillDataSet);
end;

procedure DataOwner.FillDataSet();
begin
    MyData := processResponse(MyRESTRequest.Response);
end;
Run Code Online (Sandbox Code Playgroud)

如果您想并行触发多个请求,则需要多次使用此模式。不幸的是,我们无法直接访问完成处理程序中的 TRESTRequest 实例或 TRESTResponse 实例,因为这意味着我们必须自己进行簿记。换句话说,程序员需要确保 Completion Handler 处理正确的 Response 对象。