在Delphi 10.1柏林,我正在制作一款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 ..的评论
它不是我认为的baterry生活(但我不确定),因为如果我使用线程而不是像这样的计时器:
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),这个手指或不在屏幕上。
答案 0 :(得分:11)
与VCL' TTimer
不同,Android上的FMX' TTimer
效率非常低。
当计时器间隔过去时,Android会使用回调函数(在Androidapi.Timer
单元中)通知FMX。该回调由工作线程调用,并将计时器推送到线程安全队列中(在FMX.Platform.Android
单元中)。
当主UI线程定期检查挂起的UI消息时,它还会检查计时器队列,如果任何计时器排队,则调用其OnTimer
事件处理程序(按照它们排队的顺序)。
但是,如果没有待处理的UI消息,FMX可能会延迟检查计时器队列!然后,一旦处理完所有UI消息,在再次处理事件之前可能会有延迟。这一切都取决于FMX应用程序的内部状态。
因此,无法保证1 ms定时器会以1 ms的间隔触发其OnTimer
事件处理程序。它还可以解释为什么增加UI活动可以让OnTimer
事件更频繁地触发,因为UI消息的处理频率更高。
这与VCL的TTimer
不同,后者基于WM_TIMER
UI消息,该消息是仅在没有其他UI消息待处理时生成的低优先级消息。生成它时,它会直接发送到TTimer
的内部窗口,不需要额外的排队来添加额外的开销层。但是,UI活动的增加会减慢TTImer.OnTimer
事件的触发速度,而不是加快速度。
在TThread.Synchronize()
的情况下,只要需要处理挂起的同步请求,它就会主动通知主UI线程,从而允许主UI线程更快地检查和执行同步程序,而不是后面。