在 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 毫秒触发一次。
谁能给我解释一下这种奇怪的行为?
为什么当我的手指触摸屏幕时,应用程序(或至少是计时器) react 更灵敏?如何使应用程序始终具有这种 react 性?
关于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 毫秒触发一次(没有每 1 毫秒 TThread.synchronize),并且这个手指是否在屏幕上。
最佳答案
与 VCL 的 TTimer
不同,FMX 在 Android 上的 TTimer
效率很低。
当计时器间隔结束时,Android 使用回调函数(在 Androidapi.Timer
单元中)通知 FMX。该回调由工作线程调用,并将计时器插入线程安全队列(在 FMX.Platform.Android
单元中)。
当主 UI 线程定期检查挂起的 UI 消息时,它还会检查计时器队列,如果有任何计时器排队,则调用它们的 OnTimer
事件处理程序(按照它们被调用的顺序)排队)。
但是,如果没有待处理的 UI 消息,FMX 可能会延迟检查计时器队列!然后,一旦处理完所有 UI 消息,再次处理事件之前可能会有延迟。这完全取决于 FMX 应用程序的内部状态。
因此,无法保证 1 毫秒计时器会在接近 1 毫秒间隔的任何地方触发其 OnTimer
事件处理程序。它还可以解释为什么 UI Activity 的增加可以让 OnTimer
事件更频繁地触发,因为 UI 消息被更频繁地处理。
这与VCL的TTimer
不同,后者是基于WM_TIMER
UI消息,是一个低优先级的消息,只有在没有其他UI消息时才会产生待办的。当它生成时,它会直接被分派(dispatch)到 TTimer
的内部窗口,没有额外的排队来增加额外的开销层。但是,UI Activity 的增加会减慢 TTImer.OnTimer
事件的触发速度,而不是加快它的速度。
在 TThread.Synchronize()
的情况下,每当需要处理挂起的同步请求时,它会主动通知主 UI 线程,从而允许主 UI 线程检查并执行同步'尽早完成程序。
关于android - 为什么当手指触摸屏幕时 Android 上的计时器更准确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45949296/