Почему таймер на Android более точен, когда палец касается экрана?


В 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 МС вместо этого.

Может ли кто-нибудь объяснить мне это странное поведение?

Почему приложение (или, по крайней мере, таймер) более реагирует, когда мой палец касается экрана? Как сделать так, чтобы приложение всегда было таким реактивным?

О замечании Дж..

Я думаю, что это не baterry life (но я не уверен), потому что если я использую поток вместо таймера, как это:

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.синхронизировать каждые 1 мс), а этот палец или нет на экране.

1 3

1 ответ:

В отличие от VCL TTimer, FMX TTimer на Android довольно неэффективен.

Когда интервал таймера истекает, Android уведомляет FMX с помощью функции обратного вызова (в блоке Androidapi.Timer). Этот обратный вызов вызывается рабочим потоком, и он помещает таймер в потокобезопасную очередь (в блоке FMX.Platform.Android).

Когда основной поток пользовательского интерфейса периодически проверяет наличие ожидающих сообщений пользовательского интерфейса, он также проверяет очередь таймера, и если какие-либо таймеры поставлены в очередь, то вызываются их обработчики событий OnTimer (в распорядитесь, чтобы они были поставлены в очередь).

Однако, если нет ожидающих сообщений пользовательского интерфейса, FMX может задержать проверку очереди таймера! А затем, как только все сообщения пользовательского интерфейса будут обработаны, может возникнуть задержка перед повторной обработкой событий. Все зависит от внутреннего состояния приложения FMX.

Таким образом, нет никакой гарантии, что таймер с интервалом в 1 мс запустит обработчик событий OnTimer с интервалом в 1 мс. И это также может объяснить, почему увеличение активности пользовательского интерфейса может позволить OnTimer событие срабатывает чаще, потому что сообщения пользовательского интерфейса обрабатываются чаще.

Это отличается от VCL TTimer, который основан на сообщении пользовательского интерфейса WM_TIMER, которое является низкоприоритетным сообщением, которое генерируется только тогда, когда нет других ожидающих сообщений пользовательского интерфейса. И когда он генерируется, он отправляется непосредственно во внутреннее окно TTimer, нет никакой дополнительной очереди, чтобы добавить дополнительные слои накладных расходов. Но увеличение активности пользовательского интерфейса замедлит событие TTImer.OnTimer из стрелять, а не ускорять его.


В случае TThread.Synchronize(), он активно уведомляет основной поток пользовательского интерфейса, когда ожидающий запрос синхронизации должен быть обработан, таким образом позволяя основному потоку пользовательского интерфейса проверять и выполнять процедуры sync'ed раньше, чем позже.