In Delphi 10.1 Berlin, I'm making an Android app. I created a timer like this:
fTimer := TTimer.Create(nil);
fTimer.Interval := 1;
fTimer.OnTimer := OnTimer;
fTimer.Enabled := True;
In the OnTimer
event, I simply do this:
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;
When I launch the app, the OnTimer
event is fired every 10 ms instead of every 1 ms. However, if I touch the screen and move my finger around it, the event is fired every 1.3-1.5 ms instead.
Can someone explain this strange behavior to me?
Why is the app (or at least the timer) more reactive when my finger is touching the screen? How do I make the app always be this reactive?
About the remark of J..
it's not baterry life i think (but i m not sure) because if I use a thread instead of a timer like this :
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;
Then it's work ok, the event is fired every 2 ms (without TThread.synchronize every 1ms), and this finger or not on the screen.
Unlike VCL's
TTimer
, FMX'sTTimer
on Android is quite inefficient.When the timer interval elapses, Android notifies FMX using a callback function (in the
Androidapi.Timer
unit). That callback is called by a worker thread, and it pushes the timer into a thread-safe queue (in theFMX.Platform.Android
unit).When the main UI thread checks for pending UI messages periodically, it also checks the timer queue, and if any timers are queued then their
OnTimer
event handlers are called (in the order that they have been queued).However, if there are no pending UI messages, FMX may delay checking the timer queue! And then once all UI messages have been processed, there may be a delay before events are processed again. It all depends on the internal state of the FMX app.
So, there is no guarantee whatsoever that a 1 ms timer will fire its
OnTimer
event handler anywhere near 1 ms intervals. And it might also explain why an increase in UI activity can allow theOnTimer
event to fire more often, because UI messages are being processed more often.This differs from VCL's
TTimer
, which is based on theWM_TIMER
UI message, which is a low-priority message that is only generated when there are no other UI messages pending. And when it is generated, it gets dispatched directly to theTTimer
's internal window, there is no additional queuing involved to add extra layers of overhead. But, an increase in UI activity will slow down theTTImer.OnTimer
event from firing, not speed it up.In the case of
TThread.Synchronize()
, it actively notifies the main UI thread whenever a pending sync request needs to be handled, thus allowing the main UI thread to check for and execute sync'ed procedures sooner rather than later.