2014-12-03 109 views
8

我在Rad Studio XE7中構建了一個Firemonkey應用程序,在單擊按鈕時,我需要使用TRestRequest執行多個(大約7個)Web服務調用。每個Web服務都會返回json對象,然後填充數據集。 我正在尋找同時調用這些調用的方式,並且沒有要鎖定的應用程序UI。與FireMonkey並行的多個REST請求

你推薦這樣做的方式?我看到Embarcadero爲線程引入了新的任務和特性功能,但我仍然不確定我們是否可以使用該功能以及如何使用它。另外,我看到有使用此函數異步執行TRestRequest,功能:

function TCustomRESTRequest.ExecuteAsync(ACompletionHandler: TCompletionHandler = nil; ASynchronized: boolean = true; AFreeThread: boolean = true): TRESTExecutionThread; 

,但我無法找到如何使用此方法和它做什麼的任何文件。

任何輸入將不勝感激。

+0

@JerryDodge不是異步暗示它不會阻止?最終,異步操作將終止,並且應用程序可以對結果進行一些操作。 – mjn 2014-12-03 19:31:17

+0

@mjn這個按鈕點擊我們將調用這7個Web服務的地方實際上會打開一個多視圖,在我們的例子中將包含一堆過濾組合框,這些組合框將通過從Web服務獲取數據來填充。我的想法是讓用戶能夠實際取消該過濾,然後通過觸摸多視圖之外的區域返回,這將關閉多視圖並且不應用任何過濾器。多個並行請求的想法是,如果我們並行發送7個請求,而不是一次發送一個請求,那麼我們認爲這7個組合框將更快地填充。 – Emulic 2014-12-03 21:36:45

+0

@JerryDodge您應該在後臺執行** all ** long(er)正在運行的任務,以防止UI線程被阻塞。這不僅是爲用戶,而且操作系統正在尋找沒有響應的應用程序。 – 2014-12-03 23:29:41

回答

2

ExecuteAsync(ACompletionHandler: TCompletionHandler = nil; ASynchronized: boolean = true; AFreeThread: boolean = true)方法確實是要走的路。顧名思義,它是異步的;意味着您的程序在發出請求後仍然響應,或者甚至在發出多個請求之後。
但是,從不同的對象實例中引發這些不同請求是很重要的;如果您從已經執行ExecuteAsyncTRESTRequest實例中觸發ExecuteAsync,則新請求將妨礙現有請求。您必須爲每個並行呼叫創建一個單獨的TRESTRequest實例。

請注意,它的第一個參數是一個過程;你傳遞一個你選擇的程序作爲參數。唯一的要求是程序有正確的簽名;在這種情況下,它是一個沒有參數的過程。

ExecuteAsync方法在REST.Client中定義。 (我有德爾福XE-10.1柏林,所以它有一個額外的參數,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; 

這裏會發生什麼事是,一個新的線程被創建在其中執行的REST請求。如果響應進入,則由ACompletionHandler處理。
默認情況下,ACompletionHandler在由ExecuteAsync創建的新線程上運行。如果您希望它在主線程上運行,則應將ASynchronized設置爲true

但是,您如何訪問該響應,並使其可以訪問您的程序的其餘部分?

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; 

如果你想火併聯多個請求,則需要使用這種模式幾次。不幸的是,我們沒有直接訪問我們的完成處理程序中的TRESTRequest實例或TRESTResponse實例,因爲這意味着我們必須自己做記賬。換句話說,程序員要確保完成處理程序處理正確的響應對象。