我目前正在尝试为线程创建一个统一的单元。我开发了一个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转换为范围内的变量我的应用程序主单元/表单,以及如何实际告诉应用程序线程已完成,以便我可以开始解析。
我确信这很简单,但我很感激任何帮助!
答案 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;
这使我能够将线程单元与我的应用程序单元完全分开,这对我来说是构建未来单元的真正基础。