JavaFX动画定时器和事件



我有一个AnimationTimer,我用它作为一个无限循环,如下所示:

animator = new AnimationTimer(){
@Override
public void handle(long now) {
// Update
Game.simulationStep();
// Render
Game.render();
}
}
};
animator.start();

handle函数每秒调用60次,更新一个小游戏并在场景图中渲染一些视图。

我想问自己的是,如果我有像按钮点击这样的事件,事件的代码会在循环迭代完成后执行吗?还是多线程?

问题是,我有一个游戏对象列表,它可以由事件操纵(通过点击按钮删除游戏对象(,也可以由模拟步骤中的逻辑操纵。如果事件从该列表中删除GameObjects,而simulationStep((正在对列表中的对象执行某些操作,则可能会出现问题。

答案不取决于您提供的代码,而是取决于您的其他代码。

如果代码对源自JavaFX框架的事件做出响应(比如按下按钮(,那么您不必担心,因为这些事件也在JavaFX线程上,与动画计时器相同。

您只需要担心事件是否源自JavaFX之外的其他线程。例如,来自网络聊天客户端的传入聊天消息,或者您在自己的线程上运行的AI循环。

此外,您不应该使用可能更改另一个线程上的值的属性侦听器和绑定。例如,不要从另一个线程修改用于支持列表视图的可观察列表。观察者和绑定特性的内部实现假设属性和侦听器都在一个线程上使用。同样,如果您的代码实际上是多线程的,那么这只是需要担心的事情。

如果您确实有包含源自其他线程的事件的多线程代码,请使用JavaFX并发,例如Task和/或Platform.runLater。可能与Seph的回答中的队列结合在一起,正如(在某种程度上(通过这个使用队列的多线程JavaFX日志框架所展示的那样。然而,通常不需要单独的队列,因为Platform.runLater将向JavaFX维护的内置队列中添加可运行项,以便稍后在JavaFX线程上运行。

针对您的具体问题:

我有一个游戏对象列表,它可以由事件操纵(通过点击按钮删除游戏对象(,也可以由模拟步骤中的逻辑操纵。如果事件从该列表中删除GameObjects,而simulationStep((正在对列表中的对象执行某些操作,则可能会出现问题。

否。这不会有问题。所有东西都在一个线程上运行,在simulationStep()运行时,GameObjects不能通过按钮点击来移除,因为点击处理程序和simulationStep不能同时运行。

Slaw的回答是:

  • JavaFX定期后台任务

我建议阅读关于Glass Windowing Toolkit、Threads和Pulse的JavaFX架构概述部分(两次(。该文档解释了JavaFX系统在线程、事件处理和脉冲处理方面的工作方式(AnimationTimer句柄方法由脉冲触发(。

AnimationTimer不是多线程的handle()方法在JavaFX应用程序线程上运行,所以我想如果在handle()中放入无限循环或阻塞调用,它会冻结应用程序。回答你的问题,除非你有一些在其他线程上执行的行为,否则它会很好地工作。

这里有一个相关的线程:AnimationTimer是否在自己的线程中运行?

您可以将事件添加到队列中,并在动画计时器中首先处理该队列。这应该可以避免您可能关心的任何并发或竞争条件问题,而不会损害任何实际不存在的东西。

animator = new AnimationTimer(){
@Override
public void handle(long now) {
//Process
Game.processEvents();
// Update
Game.simulationStep();
// Render
Game.render();
}
}
};
animator.start();

最新更新