12

When loading in a new FXML and setting the center of a BorderPane there is a brief 'freeze' of the application where existing animation, whether from a Timeline, or from a gif in an image view, will stop. I'm using this code to change the 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();
    }

And while this does the job in keeping the UI responsive in the load time, when the center stage displays for the first time there is a noticable lag. Looking at a CPU profile:

enter image description here

I'm not sure if the delay is from the initialize function running, or the loading of the elements. Here's a gif of the program, you can see the visible delay:

enter image description here

By loading it up in VLC and progresing frame-by-frame the delay looks to be 5 or 6 frames in a 30 fps video, meaning about a 200ms delay which implies the animation freezes for more than the 50ms or so initialize method. (Maybe the entire load method freezes the animation?)

The question is, is it possible to keep the animation smooth during this?

//********* EDIT **********//

So I went through the project and cut out as many methods and classes as possible, reducing the entire game to 6 minimal classes. I STILL have the delay in pressing the character button ('you' button). With such a minimal example I'm lost to what could be wrong. I've uploaded this to google drive for anyone to take a look.

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

12
  • 2
    Since you are performing the load on a separate thread it shouldn't cause the UI thread to stutter and the profiling info for that thread aren't really relevant. OTOH, I am surprised it works, as FXML loading and node initialization mostly need to be done on the UI thread. Can you share the code of the relevant initialize method? Commented Jun 17, 2018 at 8:58
  • 2
    The freeze is caused from getMainUI().setCenter(loadTask.getValue()); inside the setOnSucceeded() and only once, i mean if you run the process again removing the center and add it again there isnt any kind of lag. And this has nothing to do about the FXML also cause if for example you skip the FXML loading and just set a TextField on the center you will notice a smaller lag again. Commented Jun 22, 2018 at 17:55
  • 2
    Also wrapping the the code getMainUI().setCenter(loadTask.getValue()); with a Platform.runLater change nothing at all. The problem appear to be more or less a rendering issue of JavaFX of the Node you set on center of the BorderPane, which cause the main UI to freeze. Commented Jun 22, 2018 at 18:07
  • 1
    I was thinking about it a lot and the problem seems to be the rendering of the node you are trying to add on center. Even if you try to make a new stage instead of setting the node to the center of your main stage the freeze will happened again. I would like to check the code more but right now I am unable to. I will give it a look tomorrow and let you know if I find anything. Commented Jun 23, 2018 at 10:45
  • 1
    I had a chance to check your code again, there are a lot of things that I don't like to be honest. The fact that almost every method, field and UI element are static is something no one will recommend. In addition, you have a master controller which you share with multiple viewer which is really a bad idea/architecture but not only you define that controller through FXML, you also create and use an instance of it through Java code. Still with all the above, I can't say for sure that what is causing the lagging effect. Commented Jun 25, 2018 at 18:11

1 Answer 1

2
+200

There is nothing "wrong" with your code (at least in regards to this issue).

The issue you are experiencing also has nothing to do with the loading of the FXML (which is very slow and you have correctly handled off FX-Thread).

The stutter happens for These reasons:

  • relativly large hierarchy in character.fxml
  • lots of CSS (delete the main.css and you will notice; the stutter is slightly less prominent)
  • dynamically changing the scene graph (adding/removing Nodes during runtime)

Every time you replace the center of the mainView with some large Node, it causes the JavaFx runtime to completely re-layout and re-style (at least) that node. This happens on the FX-Thread, hence you notice the stutter.

One possible mitigation is a classic game dev technique: Pre-allocating as much as possible. Simply load all necessary FMXLs once during startup and put them into the scene graph. In your click handlers then, change the visibility or (Z-)position of the Nodes you want to show/hide. This is a good use case for a StackPane for example.

I adapted your code a little to demonstrate what I mean: Prototype

Check out these ressources to learn more:

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the detailed explanation, the example, and the further reading. I appreciate you taking the time (and the other commentators) greatly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.