2017-08-29 10 views
3

デルファイ10.1ベルリンでは、私はAndroidアプリを作っています。 指が画面に触れたときに、Androidのタイマーがより正確なのはなぜですか?

procedure TMyForm.OnTimer(Sender: TObject); 
begin 
    MyStopWatch.Stop; 
    Inc(acounter); 
    if acounter mod 1000 = 0 then 
    allog('delay', FloatToStr(xStopWatch.Elapsed.TotalMilliseconds)); 
    MyStopWatch := TStopWatch.StartNew; 
end; 

私はアプリを起動すると、 OnTimerイベントは10 msごとの代わりに、1ms毎に解雇されています。私は単にこれを行う、 OnTimerイベントで

fTimer := TTimer.Create(nil); 
fTimer.Interval := 1; 
fTimer.OnTimer := OnTimer; 
fTimer.Enabled := True; 

:私はこのようなタイマーを作成しました。 しかし、私が画面に触れ、その上で指を動かすと、、イベントは1.3-1.5ミリ秒ごとに発砲されます。

誰かが私にこの奇妙な行動を説明できますか?

指が画面に触れたときにアプリ(または少なくともタイマー)が反応するのはなぜですか?どのようにしてこのアプリを常に反応させるのですか? Jの発言について

...

私が代わりにこのようなタイマーのスレッドを使用している場合ので、それは私が考える(しかし、イムわからない)baterry人生ではありません。

TThread.createAnonymousThread(
    procedure 
    var MyStopWatch: TstopWatch; 
     acounter: integer; 
    begin 

    acounter := 0; 
    MyStopWatch := TStopWatch.StartNew; 

    while True do begin 
     TThread.synchronize(nil, 
     procedure 
     begin 
      MyStopWatch.Stop; 
      Inc(acounter); 
      if acounter mod 1000 = 0 then 
      allog('delay', FloatToStr(MyStopWatch.Elapsed.TotalMilliseconds)); 
      MyStopWatch := TStopWatch.StartNew; 
     end); 
     sleep(1); 
    END; 

    end).start; 

その後それは大丈夫です、イベントは2ミリ秒ごとに(1ミリメートル毎にTThread.synchronizeせずに)発射され、この指がスクリーン上にあるかどうかはわかりません。

+1

タイマーは時間の経過を記録するために使用されることは決してありません。名前を欺くことはできません。 'Interval'は実行間の最小遅延です。タイマーは決して正確な時間にロックされません。時間の影響を受けやすいタスクがある場合は、タイマーの曖昧な遅延ではなく、システム時間を使用します。 –

+0

@JerryDodge:私は完璧な精度を望んでいませんが、指が画面上にあるときは1ms、画面上に指がないときは10msの間に大きなギャップがあります!これは、例のためのスクロールの問題を引き起こします(デルファイのスクロール計算はタイマーの上部で行われます)。しかし、実際の質問:アプリが画面上の指で反応しているとき、そして最も重要なことは、いつもこれをこう反応させる方法です。 – andrey

+0

@ヴィクトリア:分かりませんか?あなたは何の研究をしましたか?私はこの質問についてもいくつかの調査をしましたが、すべてを見つけることはありません。私はこのアカウントしか持っていません... – andrey

答えて

11

VCLのTTimerとは異なり、AndroidのFMXのTTimerは非常に非効率的です。

タイマーの時間が経過すると、Androidはコールバック関数(Androidapi.Timerユニット内)を使用してFMXに通知します。そのコールバックはワーカースレッドによって呼び出され、タイマーをスレッドセーフキュー(FMX.Platform.Androidユニット内)にプッシュします。

メインUIスレッドが保留中のUIメッセージを定期的にチェックすると、タイマーキューもチェックされ、タイマーがキューに登録されている場合は、キューに入れられた順番でOnTimerイベントハンドラが呼び出されます。

しかし、保留中のUIメッセージがない場合、FMXはタイマーキューのチェックを遅らせることがあります。そして、すべてのUIメッセージが処理されると、イベントが再び処理されるまでに時間がかかることがあります。それはすべてFMXアプリの内部状態に依存します。

したがって、1 msタイマーは、1 ms間隔の近くの任意の場所にあるOnTimerイベントハンドラーを起動するという保証はありません。さらに、UIメッセージが頻繁に処理されているため、UIアクティビティが増加してより頻繁にイベントが発生する可能性がある理由についても説明します。

これは、WM_TIMER UIメッセージに基づくVCLのTTimerとは異なります。このメッセージは、保留中の他のUIメッセージがない場合にのみ生成される低優先度メッセージです。それが生成されると、それはTTimerの内部ウィンドウに直接送られます。余分なオーバーヘッドのレイヤーを追加するための追加のキューイングはありません。しかし、UIのアクティビティが増加すると、イベントが遅くなるのではなく遅くなります。TThread.Synchronize()の場合


、それは積極的に保留中の同期要求は、このようにするためのチェックとすぐにではなく、後でsync'edプロシージャを実行するためのメインUIスレッドを可能にする、処理する必要があるときはいつでもメインUIスレッドに通知します。

+0

親愛なる@RemyLebeau、私は控えめではない、あなたは言う "しかし、保留中のUIメッセージがない場合、FMXはタイマーキューのチェックを遅らせるかもしれない! ... TPlatformAndroid.InternalProcessMessagesのソースコードを読んで、すべてのループでTTimerManager.Current.CheckSynchronizeが呼び出され、どのUIメッセージとも関連していない継ぎ目です...メインループはFAndroidApp ^まで内部処理の繰り返しです。 destroyRequested <> 0; ...だから私はそれが遅れて何も理解していない? – andrey

+0

私は間違っているかもしれません(私は確かめるためにそれをデバッグしていません)、しかし、私は 'InternalProcessMessages()'のソースを読んで、ループのトップは新しいUIメッセージが到着するためのタイムアウトで待っています残りのループコードが実行される前に実行されます。そして、FMXがより優先度の高い何かをしていないときは、優先順位の低い投票であるため、投票に時間がかかることがあります。だから私は、UIがビジーでないときにタイマーキューが遅れると思うのです。 –

+0

私もデバッグしていませんでしたし、ソースコードを読んでいました。待っているのではなく、新しいuiメッセージであれば単に "チェック"しています。彼らが新しいuiメッセージでなければ、それは同期をチェックするために行く。ですから、私はUIメッセージが普通にタイマーイベントの火を遅くするとも言えます。 – andrey

関連する問題