3

在 Delphi 10.1 Berlin,我正在制作一个 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 毫秒),并且这个手指或不在屏幕上。

4

1 回答 1

11

与 VCL 不同,Android 上的TTimerFMXTTimer效率很低。

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

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

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

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

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


在 的情况下TThread.Synchronize(),每当需要处理未决的同步请求时,它都会主动通知主 UI 线程,从而允许主 UI 线程更快地检查和执行同步的过程。

于 2017-08-29T23:28:50.177 回答