2014-01-17 2 views
2

현재 스레딩 목적으로 단일 통합 장치를 만들려고합니다. 여러 응용 프로그램에서 사용할 웹 API를 개발했습니다. 스레드의 의도는 기본 응용 프로그램 스레드를 사용하지 않고 API에서 데이터를 가져 오는 것입니다. (즉, 좋은 UX를 위해 스레드로 오프 로딩). 결과는 JSON이 API에 대한 POST 요청을 사용하여 검색되며 거기에서 파싱이 수행됩니다.스레드 유닛 - 기본 응용 프로그램으로 출력

내가 작성한 모든 유닛을 가지고 있지만 실제 응용 프로그램에서 출력을 검색하는 방법을 파악하는 데 어려움을 겪고 있습니다. JSON을 스레드에서 응용 프로그램으로 전송하는 방법을 고민하고 있습니다.

내가 필요한 것은 어딘가에 '출력 변수'를 추가하는 것이지만,이 장치가 독립형 일 때 내가 어떻게하는지 확신 할 수 없다. 보통 한 단위로 모두 쓸 것이며 물론 출력 할 수도있다. 거기에있는 전역 변수에.

내 스레드 단위입니다.

unit TCAPI_ThreadLib; 

interface 

uses 
    FMX.Types, FMX.Objects, {FMX.Dialogs,} IdHTTP, System.Classes; 

type 
    TTCAPI_GetJson_Thread = class(TThread) 
    private 
     APIHTTP : TIdHTTP; 
     FApiEmail, FApiId, FApiPassword, FCommand, FCommandParams : String; 
    protected 
     procedure Execute; override; 
     procedure Finished; 
    public 
     constructor Create(SEmail, SApiID, SAPIPassword : String); 
     destructor Destroy; override; 
    var 
     FDevGUID, FDevFN, FDevPlatform, FDevModel : String; 
     FApiDataResult : String; 
    Const 
     APIBase : String = 'http://my-web-api-url.com/api.php'; 
    end; 

implementation 

{ TTCAPI_GetJson_Thread } 
constructor TTCAPI_GetJson_Thread.Create(SEmail, SApiID, SAPIPassword: String); 
begin 
    inherited Create(True); 
    APIHTTP := TIdHTTP.Create(nil); 
    FApiEmail := SEmail; 
    FApiID := SApiID; 
    FApiPassword := SApiPassword; 
    FreeOnTerminate := True; 
end; 

destructor TTCAPI_GetJson_Thread.Destroy; 
begin 
    APIHttp.Free; 
    inherited; 
end; 

procedure TTCAPI_GetJson_Thread.Execute; 
var 
    RcvStrm : TStringStream; 
    TmpClass : String; 
    ApiCommand : String; 
    _Params : TStringList; 
begin 
    inherited; 
    RcvStrm := TStringStream.Create; 
    _Params := TStringList.Create; 
    _Params.Add('API_ID='+FApiID); 
    _Params.Add('API_EMAIL='+FApiEmail); 
    _Params.Add('API_PASSWORD='+FApiPassword); 
    APICommand := APIBase; 

    try 
    APIHTTP.Post(APICommand, _Params, RcvStrm); 
    FApiDataResult := RcvStrm.DataString; 
    finally 
    RcvStrm.Free; 
    _Params.Free; 
    end; 
    Synchronize(Finished); 
end; 

procedure TTCAPI_GetJson_Thread.Finished; 
begin 
    // ShowMessage(FApiDataResult); 
end; 

end. 

내가 FMX.Dialogs을 추가하고 스레드 단위의 ShowMessage(FApiDataResult) 전화를 사용하는 경우, 그것은 메시지 상자에 JSON을 보여줍니다 - 내가 주 내 응용 프로그램의 범위 내에서 변수로 JSON 것을 얻는 방법을 강구해야 unit/form과 실제로 쓰레드가 끝났음을 애플리케이션에 알리는 방법으로 파싱을 시작할 수 있습니다.

나는 그렇게하기 쉽지만 어떤 도움을 주셔서 감사합니다!

+0

문제는 아니지만 _Params를 무료로 사용하지 마십시오. –

+0

GUI와 상호 작용하려면'TThread.Synchronize' 또는'TThread.Queue'를 사용해야합니다. http://www.uweraabe.de/Blog/2011/01/30/synchronize-and-queue-with-parameters/ –

+0

나는 Synchronize를 사용해야한다는 것을 알고 있고 나는'Synchronize (Finished)'를 호출하고 있음을 알 수있다. 위의 내용은 스레드의 컨텍스트에서 데이터를 제공하지만 스레드 장치 코드를 기본 장치 자체에 복사하지 않고이 데이터를 주 응용 프로그램 스레드의 컨텍스트로 가져 오는 방법을 확신 할 수 없습니다. –

답변

2

좀 더 많은 연구 덕분에 콜백과 관련된 솔루션을 발견했습니다. 나중에 참조 할 수 있도록 게시 (물론 답을 구하는 다른 사람들의 지식을 공유하는 것);

unit TCAPI_ThreadLib; 

interface 

uses 
    FMX.Types, FMX.Objects, IdHTTP, System.Classes; 

type 
    TDataCallback = Procedure(const SJson : String) of Object; 

    TTCAPI_GetJson_Thread = class(TThread) 
    constructor Create(SEmail, SApiID, SAPIPassword : String; CallBack : TDataCallback); overload; 
    procedure Execute; override; 
    destructor Destroy; override; 

    private 
     APIHTTP : TIdHTTP; 
     FApiEmail, FApiId, FApiPassword, FCommand, FCommandParams : String; 
     FApiDataResult : String; 
     FDataProc : TDataCallback; 
     FDevGUID, FDevFN, FDevPlatform, FDevModel : String; 
     Procedure DoCallback; 
    public 
     Const 
     APIBase : String = 'http://my-web-api-url.com/api.php'; 
    end; 

implementation 

{ TTCAPI_GetJson_Thread } 
procedure TTCAPI_GetJson_Thread.DoCallback; 
begin 
    if Assigned(FDataProc) then FDataProc(FApiDataResult); 
end; 

constructor TTCAPI_GetJson_Thread.Create(SEmail, SApiID, SAPIPassword: String; CallBack : TDataCallback); 
begin 
    inherited Create(True); 
    APIHTTP := TIdHTTP.Create(nil); 
    FApiEmail := SEmail; 
    FApiID := SApiID; 
    FApiPassword := SApiPassword; 
    FDataProc := Callback; 
end; 

destructor TTCAPI_GetJson_Thread.Destroy; 
begin 
    APIHttp.Free; 
    inherited; 
end; 

procedure TTCAPI_GetJson_Thread.Execute; 
var 
    RcvStrm : TStringStream; 
    TmpClass : String; 
    ApiCommand : String; 
    _Params : TStringList; 
begin 
    inherited; 
    RcvStrm := TStringStream.Create; 
    _Params := TStringList.Create; 
    _Params.Add('API_ID='+FApiID); 
    _Params.Add('API_EMAIL='+FApiEmail); 
    _Params.Add('API_PASSWORD='+FApiPassword); 
    APICommand := APIBase; 

    try 
    APIHTTP.Post(APICommand, _Params, RcvStrm); 
    FApiDataResult := RcvStrm.DataString; 
    finally 
    RcvStrm.Free; 
    _Params.Free; 
    end; 
    Synchronize(DoCallback); 
end; 

end. 

내 주요 응용 프로그램 단위 내에; 내 응용 프로그램 단위에서 완전히 분리 스레딩 장치를 유지하는 저를 허용하고 나에 미래의 단위를 구축하기위한 실제 강력한 기반의 것

Procedure TForm1.DataCallback(Const S: String); 
begin 
    ShowMessage(S); 
end; 

procedure TForm1.Button2Click(Sender: TObject); 
var 
    DataThread : TTCAPI_GetJson_Thread; 
begin  
    With TTCAPI_GetJson_Thread.Create('[email protected]','apiid','password', DataCallback) do 
    begin 
    FreeOnTerminate := True; 
    Start; 
    end;  
end; 

.

+2

향후 (잠재적 인) 비 VCL 응용 프로그램에서 장치를 재사용하려면 콘솔 응용 프로그램 및 기타 사례 (예 : 서비스 유형 응용 프로그램)에서 Synchronize()를 생략 할 수 있습니다 (http://stackoverflow.com/questions/10689159/ 참조). 비 - 비 - 동기 - 비 - 응용 - 비 - 동기 - 애플리케이션 – mjn