【问题标题】:Animation in FMX main thread stops when worker thread starts当工作线程启动时,FMX 主线程中的动画停止
【发布时间】:2021-01-14 10:52:22
【问题描述】:

我的 FireMonkey 应用有一个保存按钮:

procedure TFormProductionRuns.buSaveFinishProductClick(Sender: TObject);
begin
  ShowActivity;
  ITask(TTask.Create(
    procedure
    begin
      try
        TThread.Synchronize(nil,
          procedure
          begin
            PostFinishProduct;
          end);
      finally
        TThread.Synchronize(nil,
          procedure
          begin
            HideActivity;
          end);
      end;
    end)).Start;
end;

活动方法定义为:

procedure TFormProductionRuns.ShowActivity;
begin
  frProgress1.ShowActivity;
end;

procedure TFormProductionRuns.HideActivity;
begin
  frProgress1.HideActivity;
end;

procedure TfrProgress.ShowActivity;
begin
  Self.Visible := True;
  ProgFloatAnimation.Enabled := True;
end;

procedure TfrProgress.HideActivity;
begin
  ProgFloatAnimation.Enabled := False;
  Self.Visible := False;
end;

框架设置为对齐内容,因此可见时会填满整个应用屏幕,并包含“忙碌”动画。大部分工作是对 post web 方法的 REST 请求。

procedure TFormProductionRuns.PostFinishProduct;
var
  AList: TObjectList<TFinishedProduct>;
  sReqBody, sResponse: String;
begin

  ...

  sReqBody := TJSONUtils.ObjectsToJSONArray<TFinishedProduct>(AList).ToString;
  RESTReqPostTransaction.Params.ParameterByName('ReqBody').Value := sReqBody;

  RESTClient1.Params.ParameterByName('host_port').Value := FLoginInfo.Server + ':' + FLoginInfo.Port;
  HTTPBasicAuthenticator1.Username := FLoginInfo.LoginId;
  HTTPBasicAuthenticator1.Password := FLoginInfo.LoginPw;
  
  try
    RESTReqPostTransaction.Execute;
  except on E:Exception do
    begin
      ShowMessage('Post Finish Product failed. Exception: ' + E.Message);
      Exit;
    end;
  end;

  sResponse := RESTResponseFromPost.Content;

  ...

end;

我发现动画在处理此请求时停止,但我的理解是主线程会在工作线程等待响应时继续。

该应用确实有一个类似的方法,它使用 Get REST 请求而不是 Post,并且在工作线程运行时为“忙碌”图形设置动画没有问题等待回复。

【问题讨论】:

  • 在调用周围使用 Synchronize 意味着您最好不要使用线程。只有在工作完成后有必要时才进行同步以将结果传回。
  • TTask 在主线程中完成所有工作,因此动画当然会被阻止。不要使用Synchronize() 运行TTask 的操作。仅在访问共享资源、UI 控件等或将通知/更新发送回主线程时使用它(在后一种情况下,请考虑改用 TThread.Queue())。
  • 感谢 cmets 和回答。我所做的编码是基于 Embarcadero 提供的医疗保健行业模板 FireMonkey 项目。我将研究以不同的方式实现该过程,我仍然希望等待 REST 请求完成,然后再允许用户执行任何其他操作,但我不想阻止主线程执行动画。跨度>

标签: multithreading rest delphi firemonkey


【解决方案1】:

TThread.Synchronize 是一个请求主线程执行同步参数中的方法的方法。这实际上完全击败了多线程。

您必须设计您的线程,以便同步仅用于非常短的操作,例如更新用户界面或在工作线程和主线程之间传递数据,因为当调用同步时,线程正在等待(它已停止)用于传入参数的方法将由主线程执行。当主线程执行该方法时,它什么也不做(而且你的动画停止了)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多