Delphi XE5 Android Indy TIDNotify未执行

Delphi XE5 Android Indy TIDNotify未执行,android,delphi,indy,firemonkey,delphi-xe5,Android,Delphi,Indy,Firemonkey,Delphi Xe5,我已经将代码简化为一个简单的示例。 IdTCPClient读取消息并将其显示在备忘录中。 附加的代码在Windows上运行良好,但是如果从ThC\u Receive调用PostLog,则不会在android上执行DoNotify。如果我通过按钮调用PostLog。单击main表单中的,它将被执行。 有什么建议吗? TIdSync可以工作,但建议使用它吗 unit HeaderFooterTemplate; interface uses System.SysUtils, System.Ty

我已经将代码简化为一个简单的示例。
IdTCPClient
读取消息并将其显示在备忘录中。 附加的代码在Windows上运行良好,但是如果从
ThC\u Receive
调用
PostLog
,则不会在android上执行
DoNotify
。如果我通过
按钮调用PostLog。单击
main表单中的
,它将被执行。 有什么建议吗? TIdSync可以工作,但建议使用它吗

unit HeaderFooterTemplate;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,   IdContext, IdSync,
  FMX.Layouts, FMX.Memo, IdThreadComponent, IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, IdGlobal;

type
  // ---------------------------------------------------------------------------
  TLog = class(TIdNotify)
  protected
    fMsg: String;
    procedure DoNotify; override;
    //procedure DoSynchronize; override;
  public
    class procedure PostLog(const S: String);
  end;

  // ---------------------------------------------------------------------------
  THeaderFooterForm = class(TForm)
    Header: TToolBar;
    Footer: TToolBar;
    HeaderLabel: TLabel;
    M_Log: TMemo;
    IdTCPClient1: TIdTCPClient;
    ThC_Receive: TIdThreadComponent;
    Button2: TButton;
    procedure Button2Click(Sender: TObject);
    procedure IdTCPClient1Connected(Sender: TObject);
    procedure ThC_ReceiveRun(Sender: TIdThreadComponent);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  HeaderFooterForm: THeaderFooterForm;

implementation

{$R *.fmx}

// -----------------------------------------------------------------------------
{ TLog }
// -----------------------------------------------------------------------------
procedure TLog.DoNotify;
begin
  HeaderFooterForm.M_Log.Lines.Append(fMsg);
end;

// -----------------------------------------------------------------------------
class procedure TLog.PostLog(const S: String);
begin
  with Create do
  begin
    try
      fMsg := S;
      Notify;
    except
      Free;
      Raise;
    end;
  end;
end;

// -----------------------------------------------------------------------------
procedure THeaderFooterForm.Button2Click(Sender: TObject);
begin
  try
    IdTCPClient1.Host :='192.168.1.12';
    IdTCPClient1.Port := 1001;
    IdTCPClient1.Connect;
  except
      on E: Exception do
      begin
        TLog.PostLog(trim(e.Message));
        Raise;
      end;
  end;
end;

// -----------------------------------------------------------------------------
procedure THeaderFooterForm.IdTCPClient1Connected(Sender: TObject);
begin
  ThC_Receive.Start;
end;

// -----------------------------------------------------------------------------
procedure THeaderFooterForm.ThC_ReceiveRun(Sender: TIdThreadComponent);
var
  s: string;

begin
  try
    s:= (IdTCPClient1.IOHandler.ReadLn(TransmissionSeparator, IndyTextEncoding(IdTextEncodingType.encUTF16LE)));
      TLog.PostLog(trim(s));
  except
    on E: Exception do
    begin
      TLog.PostLog(trim(e.Message));
      Raise;
    end;
  end;
end;

// -----------------------------------------------------------------------------
end.
谢谢,,
Spectro

在工作线程中调用时,
TIdNotify
使用
TThread.Queue()
TIdSync
使用
TThread.Synchronize()
,两者都通过相同的RTL队列,因此
TThread.Synchronize()
不太可能工作,但
TThread.Queue()
不工作。另一方面,在主线程中调用时,不使用
TThread
(除非
TIdNotify.mainthreausesnotify
设置为true),而是直接调用
TIdNotify.DoNotify()
TIdSync.DoSynchronize()
。如果
TIdNotify
在线程中不工作,则必须中断
TThread.Queue()
,这将是Embarcadero问题,而不是Indy问题

也就是说,
TIdNotify
确实有逻辑在没有可用
TThread.Queue()
的Delphi版本上使用
TThread.Synchronize()
。您可以尝试复制
IdSync.pas
并对其进行修改,以在Android上取消定义
HAS\u STATIC\u TThread\u Queue
定义,然后将修改后的文件添加到项目中。不过,这仅在禁用运行时包时有效。我不是Android开发者,所以我不知道Delphi如何在移动平台上使用软件包

顺便说一句,
IndyTextEncoding(idtextcodingtype.encUTF16LE)
可以替换为
IndyTextEncoding\u UTF16LE

更新:FireMonkey本身已经发现了一个bug(请参阅),它可以追溯到FireMonkey首次引入的时候,并且仍然存在于XE5更新2中。简而言之,
FMX.TApplication
不会将处理程序分配给
System.Classes.WakeMainThread
回调(
Vcl.TApplication
会)
TThread
调用
WakeMainThread
通知主线程一个
Synchronize/Queue()
请求挂起。因此,如果在调用
Synchronize/Queue()
时主消息循环处于空闲状态,则在以后的某个时间如果/当其他内容将新消息放入主消息队列时,不会发生任何事情。如果没有该选项,则不会调用
TApplication.Idle()
,因此不会调用
CheckSynchronize()
来处理挂起的
Synchronize/Queue()
请求。这意味着对于后台/非可视进程,
Synchronize/Queue()
可能根本无法正常工作,而且偶尔会在GUI进程中正常工作。在Embarcadero修复该错误之前,解决方法是将自定义消息发布到主消息队列以“唤醒”它,或者在主线程中定期手动调用
CheckSynchronize()
,例如在计时器中