Почему таймер на 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 ответ:
В отличие от VCL
Когда интервал таймера истекает, Android уведомляет FMX с помощью функции обратного вызова (в блокеTTimer
, FMXTTimer
на Android довольно неэффективен.Androidapi.Timer
). Этот обратный вызов вызывается рабочим потоком, и он помещает таймер в потокобезопасную очередь (в блокеFMX.Platform.Android
).Когда основной поток пользовательского интерфейса периодически проверяет наличие ожидающих сообщений пользовательского интерфейса, он также проверяет очередь таймера, и если какие-либо таймеры поставлены в очередь, то вызываются их обработчики событий
OnTimer
(в распорядитесь, чтобы они были поставлены в очередь).Однако, если нет ожидающих сообщений пользовательского интерфейса, FMX может задержать проверку очереди таймера! А затем, как только все сообщения пользовательского интерфейса будут обработаны, может возникнуть задержка перед повторной обработкой событий. Все зависит от внутреннего состояния приложения FMX.
Таким образом, нет никакой гарантии, что таймер с интервалом в 1 мс запустит обработчик событийOnTimer
с интервалом в 1 мс. И это также может объяснить, почему увеличение активности пользовательского интерфейса может позволитьOnTimer
событие срабатывает чаще, потому что сообщения пользовательского интерфейса обрабатываются чаще.Это отличается от VCL
TTimer
, который основан на сообщении пользовательского интерфейсаWM_TIMER
, которое является низкоприоритетным сообщением, которое генерируется только тогда, когда нет других ожидающих сообщений пользовательского интерфейса. И когда он генерируется, он отправляется непосредственно во внутреннее окноTTimer
, нет никакой дополнительной очереди, чтобы добавить дополнительные слои накладных расходов. Но увеличение активности пользовательского интерфейса замедлит событиеTTImer.OnTimer
из стрелять, а не ускорять его.
В случае
TThread.Synchronize()
, он активно уведомляет основной поток пользовательского интерфейса, когда ожидающий запрос синхронизации должен быть обработан, таким образом позволяя основному потоку пользовательского интерфейса проверять и выполнять процедуры sync'ed раньше, чем позже.