首页 > 解决方案 > 加载/显示 FXML 时避免动画中出现短暂的卡顿

问题描述

在加载新的 FXML 并设置 BorderPane 的中心时,应用程序会短暂“冻结”,现有动画(无论是来自时间轴还是来自图像视图中的 gif)都将停止。我正在使用此代码来更改 centerView:

 @FXML
    public void handleChangeView(ActionEvent event) {
        Task<Parent> loadTask = new Task<>() {
            @Override
            public Parent call() throws IOException {

                String changeButtonID = ((ToggleButton) event.getSource()).getId();
                Parent newOne = getFxmls().get(changeButtonID);

                if (newOne == null) {
                    FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/" + changeButtonID + ".fxml"));
                    newOne = loader.load();
                    getFxmls().put(changeButtonID, newOne);
                }
                return newOne ;
            }
        };

        loadTask.setOnSucceeded(e -> {
                    getMainUI().setCenter(loadTask.getValue());
        });

        loadTask.setOnFailed(e -> loadTask.getException().printStackTrace());

        Thread thread = new Thread(loadTask);
        thread.start();
    }

虽然这可以在加载时保持 UI 响应,但当中心舞台第一次显示时,会有明显的延迟。查看 CPU 配置文件:

在此处输入图像描述

我不确定延迟是来自初始化函数的运行还是元素的加载。这是程序的 gif,您可以看到可见的延迟:

在此处输入图像描述

通过在 VLC 中加载并逐帧进行,延迟看起来是 30 fps 视频中的 5 或 6 帧,这意味着大约 200 毫秒的延迟,这意味着动画冻结超过 50 毫秒左右的初始化方法。(也许整个加载方法会冻结动画?)

问题是,在此期间是否可以保持动画流畅?

//********* 编辑 **********//

所以我通过这个项目,尽可能多地删减方法和类,将整个游戏减少到 6 个最小类。我仍然有按下字符按钮(“你”按钮)的延迟。有了这样一个最小的例子,我迷失了可能出错的地方。我已将其上传到谷歌驱动器供任何人查看。

https://drive.google.com/open?id=17A-PB2517bPJc8Dek-yp2wGXsjTyTj1d

标签: javajavafxjavafx-8

解决方案


您的代码没有任何“错误”(至少在这个问题上)。

您遇到的问题也与 FXML 的加载无关(这很慢,您已经正确处理了 FX-Thread)。

出现口吃的原因如下:

  • 相对较大的层次结构character.fxml
  • 大量的 CSS(删除main.css你会注意到;口吃稍微不那么突出)
  • 动态改变场景图(在运行时添加/删除节点)

每次用一些大节点替换 的centermainView,都会导致 JavaFx 运行时完全重新布局和重新设置(至少)该节点的样式。这发生在 FX 线程上,因此您会注意到口吃。

一种可能的缓解措施是一种经典的游戏开发技术:尽可能多地预先分配。只需在启动期间加载所有必要的 FMXL 并将它们放入场景图中。然后在您的点击处理程序中,更改要显示/隐藏的节点的可见性或(Z-)位置。例如,这是一个很好的用StackPane例。

我稍微修改了您的代码以说明我的意思: 原型

查看这些资源以了解更多信息:


推荐阅读