为什么 Android 上的计时器在手指触摸屏幕时更准确?

Why is a Timer on Android more accurate when a finger is touching the screen?

在 Delphi 10.1 柏林,我正在制作一个 Android 应用程序。我创建了一个这样的计时器:

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

OnTimer事件中,我只是这样做:

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 毫秒触发一次,而不是每 1 毫秒触发一次。 但是,如果我触摸屏幕并在屏幕上移动手指,则该事件每 1.3-1.5 毫秒触发一次。

谁能给我解释一下这种奇怪的行为?

为什么当我的手指触摸屏幕时,应用程序(或至少计时器)反应更灵敏?如何让应用程序始终如此反应灵敏?

关于J..的评论

我认为这不是电池寿命(但我不确定),因为如果我使用线程而不是像这样的计时器:

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 毫秒触发一次(没有 TThread.synchronize 每 1 毫秒触发一次),并且这个手指是否在屏幕上。

与 VCL 的 TTimer 不同,FMX 在 Android 上的 TTimer 效率很低。

当计时器间隔结束时,Android 使用回调函数通知 FMX(在 Androidapi.Timer 单元中)。该回调由工作线程调用,并将计时器推入线程安全队列(在 FMX.Platform.Android 单元中)。

当主 UI 线程定期检查未决 UI 消息时,它还会检查计时器队列,如果有任何计时器排队,则调用它们的 OnTimer 事件处理程序(按照他们排队的顺序)。

但是,如果没有待处理的 UI 消息,FMX 可能会延迟检查计时器队列!然后,一旦处理了所有 UI 消息,再次处理事件之前可能会有延迟。这完全取决于 FMX 应用程序的内部状态。

因此,无法保证 1 毫秒计时器会在接近 1 毫秒间隔的任何地方触发其 OnTimer 事件处理程序。它也可以解释为什么 UI activity 的增加可以让 OnTimer 事件更频繁地触发,因为 UI 消息被更频繁地处理。

这与VCL的TTimer不同,它基于WM_TIMER UI消息,是低优先级的消息,只有在没有其他UI 待处理的消息。当它生成时,它会直接被调度到 TTimer 的内部 window,没有额外的排队来增加额外的开销层。但是,增加 UI activity 会减慢 TTImer.OnTimer 事件的触发速度,而不是加快它的速度。


TThread.Synchronize() 的情况下,它会在需要处理挂起的同步请求时主动通知主 UI 线程,从而允许主 UI 线程检查和尽早执行同步程序。