2014-03-25 2 views
0

간단한 샘플 코드로 축소되었습니다. IdTCPClient은 메시지를 읽고 메모에 표시해야합니다. 첨부 된 코드는 Windows에서 제대로 작동하지만 에서 PostLog을 호출하면 DoNotify이 android에서 실행되지 않습니다. 내가 Button.Click을 통해 PostLog를 호출하면 MainForm에서 실행됩니다. 제안 사항이 있으십니까? TIdSync는 작동하지만 권장 되는가? 작업자 스레드에서 호출 할 때 Delphi XE5 Android 인디 TIDNotify가 실행되지 않았습니다.

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. 

는 분광

답변

1

감사 TIdNotifyTThread.Queue() 사용하고 TThread.Synchronize() 작동 할 가능성은 있지만, 그래서 TIdSync는 같은 RTL 큐를 통해 이동 둘 TThread.Synchronize()를 사용 TThread.Queue()은 그렇지 않습니다. 반면에 주 스레드에서 호출하면 TThread이 사용되지 않고 (TIdNotify.MainThreadUsesNotify이 true로 설정되지 않은 경우) TIdNotify.DoNotify()TIdSync.DoSynchronize()이 직접 호출됩니다. TIdNotify이 스레드에서 작동하지 않으면 TThread.Queue()이 손상되어야합니다. 이는 Indy 문제가 아닌 Embarcadero 문제 일 것입니다.

즉, TIdNotify에는 TThread.Queue()이없는 델파이 버전에서 TThread.Synchronize()을 사용하는 논리가 있습니다. IdSync.pas 사본을 만들어 Android에서 HAS_STATIC_TThread_Queue 정의를 정의 해제하도록 수정 한 다음 수정 된 파일을 프로젝트에 추가 할 수 있습니다. 하지만 런타임 패키지가 비활성화 된 경우에만 작동합니다. 필자는 안드로이드 개발자가 아니므로 델파이가 모바일 플랫폼에서 어떻게 패키지를 사용하는지 알지 못합니다.

BTW, IndyTextEncoding(IdTextEncodingType.encUTF16LE)IndyTextEncoding_UTF16LE으로 바꿀 수 있습니다.

업데이트 : 버그는 FireMonkey 자체 (QC#123579 참조)에서 확인되었습니다, 다시 모든 길을가는 FireMonkey는 처음 소개하고, 여전히 즉, FMX.TApplication이 핸들러를 할당하지 않습니다 2. XE5 업데이트에 존재 때 System.Classes.WakeMainThread 콜백 (Vcl.TApplication 않습니다). TThreadSynchronize/Queue() 요청이 보류 중임을 주 스레드에 알리기 위해 WakeMainThread을 호출합니다. 따라서 Synchronize/Queue()이 호출 될 때 주 메시지 루프가 유휴 상태이면 다른 메시지가 주 메시지 대기열에있을 때/나중에 아무 일도 일어나지 않습니다. 그것 없이는 TApplication.Idle()이 호출되지 않으므로 요청을 처리하려면 CheckSynchronize()이 호출되지 않습니다. 이는 백그라운드/넌 비주얼 프로세스를 의미하며, Synchronize/Queue()은 전혀 전혀 작동하지 않을 수도 있고, GUI 프로세스에서 산발적으로 작동하지 않을 수도 있습니다. Embarcadero가 버그를 수정하기 전까지는 주 메시지 대기열에 사용자 정의 메시지를 게시하여 "깨우거나"수동으로 CheckSynchronize()을 주 스레드에서 타이머와 같이 주기적으로 호출하는 것이 좋습니다.

관련 문제