Java 场景加载太慢

Java 场景加载太慢,java,netbeans,javafx,javafx-2,Java,Netbeans,Javafx,Javafx 2,我正在构建一个JavaFX应用程序,我想知道是否有关于如何在当前阶段中尽快加载新场景的建议(最佳实践)。 目前我所做的(或多或少)是: Parent root = (Parent)myFXLoader.load(); currentStage.setScene(new Scene (root); 对于简单的场景s,上述操作非常有效且速度足够快,但当加载初始化TableViews、组合框es等更复杂的场景时,场景s之间的转换需要很多秒,这很烦人。 我在控制器的初始化(URL,ResourceBu


我正在构建一个JavaFX应用程序,我想知道是否有关于如何在当前
阶段
中尽快加载新
场景
的建议(最佳实践)。

目前我所做的(或多或少)是:

Parent root = (Parent)myFXLoader.load();
currentStage.setScene(new Scene (root);
对于简单的
场景
s,上述操作非常有效且速度足够快,但当加载初始化
TableView
s、
组合框
es等更复杂的场景时,
场景
s之间的转换需要很多秒,这很烦人。

我在
控制器
初始化(URL,ResourceBundle rb)
方法中进行的所有初始化。
在那里,我将项目添加到
选择/组合
框中,初始化
表格视图
等,但正如我所说,这需要太多时间。
我做错什么了吗?我应该在别的地方初始化吗

非常感谢。

编辑:
任何有兴趣帮助这项工作的人,甚至想为他们的项目找到想法的人,我已经在google.com上上传了我项目的一部分(Netbeans项目)。
您可以使用SVN进行检查。这是链接:

用户名:TABLARASAFX只读
不需要密码
运行项目后的说明:
第一个屏幕是登录屏幕,只需单击确定
第二个屏幕是“主页”,在那里您可以看到treeView菜单并导航到4个不同的屏幕
我的问题是类->创建页面的加载时间。请看一下,如果您发现了什么,请告诉我

编辑:
我做了@jewelsea建议的3项更改。
1.我使用HashMap保存每个屏幕的所有控制器
2.我只更新部分场景,而不是整个场景
3.我使用的答案帮助控制器更快地加载,如答案中所述。

现在一切都快多了
请随意使用该项目作为指南
此外,我还更新了程序,以浏览3个屏幕,以便更好地理解

请注意,我的代码很混乱

场景的速度与您从一开始就试图在场景中初始化多少对象有很大关系。因此,如果您可以将该数字降至最低,并在场景运行时创建其余部分,则所有内容都将运行得更加平滑。如果在您的情况下这是不可能的,那么可以尝试限制其他事情,以减少对系统的压力。

一些背景

我看了你的项目Dimitris

我为“类创建”页面计时了您的加载创建时间(OSX10.92012MacBookAir上的Java8B129)。我只花了一秒钟多的时间

为了简化测试,我删除了使用并发服务加载新FXML的部分,并在请求时直接在JavaFX应用程序线程上加载FXML——这样做容易得多

对不起,这里的回答太长了。像这样的事情通常不适合StackOverflow,它们以教程或博客的形式结束,但我很好奇到底发生了什么,所以我想我应该花些时间研究一下并写下来

不要为加载的每个FXML创建新场景

每次加载FXML时都会设置一个新场景(具有新大小)。不管出于什么原因,这是一个相当昂贵的操作,你不需要这样做。你的舞台上已经有了一个场景,只要重复使用就可以了。因此,请替换以下代码:

stage.setScene(new Scene(service.getValue().getRoot(), service.getValue().getX(), service.getValue().getY()));
与:

这将节省超过半秒的加载时间,因此现在classes->create在第一次运行时大约需要400毫秒

这一变化是轻松赢得绩效的一个例子

它还提供了更好的用户体验,因为在我的机器上,当您更改场景时,舞台呈灰色闪烁,但当您仅替换现有场景的场景根时,没有灰色闪烁

因为JVM使用Java的实时编译器运行,后续的显示类->创建的请求速度更快,所以打开场景两三次后,大约需要250毫秒(或四分之一秒)

FXMLLoader运行缓慢

在剩下的250ms加载时间中,初始化代码大约用2ms,JavaFX渲染控件用2ms,FXMLLoader加载FXML并实例化节点进入场景用246ms

UI代码的想法是,您希望将转换的目标时间降低到<16到30ms。这将为用户提供快速平滑的过渡

将用户界面代码与网络和数据库代码分开

网络和数据库调用最好在JavaFX应用程序线程之外完成,因此您可以使用JavaFX并发工具包装这些任务。但我建议将关注点分开。使用并发服务来获取数据,但一旦数据返回,请使用Platform.runLater或任务返回值将数据传输到JavaFX应用程序线程,并在JavaFX应用程序线程上运行填充(因为填充任务无论如何都会非常快)

通过这种方式,您将系统中的多线程划分为不同的逻辑组件—网络在其自己的线程上运行,UI操作在不同的线程上运行。它使东西更容易推理和设计。把它想象成有点像web编程,其中ajax调用将数据并发地提取到UI,然后提供一个回调,调用回调将数据处理到UI中

这样做的另一个原因是,许多网络库都有自己的线程实现,所以您只需使用它,而不是生成自己的线程

如何使FXML加载更快

加载FXML文件不应该真的需要多线程代码。FXML的初始化函数运行得非常快(只有几毫秒)
stage.getScene().setRoot(service.getValue().getRoot());