线程单位 - 输出到主应用程序

时间:2014-01-17 01:37:35

标签: multithreading delphi delphi-xe5

我目前正在尝试为线程创建一个统一的单元。我开发了一个Web API,我打算在多个应用程序中使用它。我对该线程的意图是在不使用主应用程序线程的情况下从API获取数据。 (即为了良好的用户体验而卸载到一个线程中)。输出将使用对API的POST请求来检索JSON,并且将从那里执行解析。

我已经把所有单元都写好了但我正在努力弄清楚如何在实际应用程序中检索输出/将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转换为范围内的变量我的应用程序主单元/表单,以及如何实际告诉应用程序线程已完成,以便我可以开始解析。

我确信这很简单,但我很感激任何帮助!

1 个答案:

答案 0 :(得分: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@example.com','apiid','password', DataCallback) do
  begin
    FreeOnTerminate := True;
    Start;
  end;    
end;

这使我能够将线程单元与我的应用程序单元完全分开,这对我来说是构建未来单元的真正基础。