如何从后台线程调用repaint可能会减慢动画速度?
问题描述:
在android下使用delphi,我有一个后台线程。在这样的背景线程我称之为同步的过程,只是做一个重绘:如何从后台线程调用repaint可能会减慢动画速度?
TThread.Synchronize(nil,
procedure
begin
repaint;
end);
恢复你的Delphi源代码,在Android的重绘简单地把一个布尔真话说到主尺蠖上重绘形式下一个循环:
procedure TPlatformAndroid.InvalidateWindowRect(const AForm: TCommonCustomForm; R: TRectF);
begin
TAndroidWindowHandle(AForm.Handle).NeedsUpdate := True;
end;
我也有我的窗体上的鼠标移动事件与我赶上鼠标移动和在那里我也呼吁重绘
procedure TMyFrame.FrameMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
begin
VPos := Y;
repaint;
end;
现在我绝对不明白,是为什么这个repaint(在后台线程)导致动画一些混蛋如果(并且只有)我也同时移动我的手指在屏幕上(如果我不要动的手指,那么我没有混蛋)
这可能是怎么可能的?因为重绘只是通过鼠标移动来实现真实的事情(反之亦然)。这怎么可以延迟一段时间超过100毫秒的调用我的框架(产生混蛋)。从后台线程删除删除的OnPaint也抽筋......不知道什么可能是错误的
注:
如果TPlatformAndroid.InternalProcessMessages
如果我更换
if TWindowManager.Current.RenderIfNeeds then
HasEvents := True
通过
TWindowManager.Current.RenderImmediately;
HasEvents := True;
然后滞后消失很多(但不完全)
答
好吧,我找出原因。
在delphi中的问题是,即使重绘是一个微不足道的操作,并将标志设置为true,下面的操作实际上可以呈现表单并不是微不足道的,无论如何(即使表单没有改变)它将需要16毫秒(vsync信号罚款)。我的问题也与ui事件有关,因为当它们是ui事件时,delphi每隔1 ms发送一个计时器而不是每10 ms
所以你可以理解,如果我在不好的时候调用repaint(例如通常必须先启动计时器),那么我们将有16ms的延迟等待,然后当计时器启动时,它会太晚,我们已经有一帧丢失(实际上不是,但最后一次涂料什么也没做),然后我们将有滞后:(
所以,如果你的线程中调用'Synchronize'一遍又一遍,你有什么样的呼叫之间的延迟或者他们”?只是bac k回来?如果没有延迟,那么你的线程基本上阻止了主线程实际上能够完成它的工作。与设置布尔值无关,以及使用'Synchronize'阻塞主线程的一切。事实上,这是使线程与主线程进行通信的方式,但是如果您一直称它为主线程,则不会让主线程有机会完成其工作。最起码拖延了,但我不知道你为什么需要这个。 –
作为一个测试,如果你在'Synchronize'中注释掉'repaint',会发生什么?你还观察到一个滞后? –
在这个例子中,让我们说一遍又一遍。不,它不能阻塞主线程,因为主循环(TPlatformAndroid.InternalProcessMessages)会执行:processUImessage,Render,processTimerEvent和processsynchronize。作为渲染采取16毫秒左右的任何情况下(opengl vsync),那么我们的同步(没有做任何事情不会使bool成为真)将每16毫秒(分钟)执行,所以没有葡萄干影响动画 – andrey