9

I have a program which loads many fxml files when executed. The application will be finished in a short time, and loading the application just takes too long.

There are many fxml files (20+) and all these fxml files are loaded with Java code. There will be a point that the application is finished and ready for use, but all files will be loaded with every execution of the program. Can the fxml files only be compiled once, because they won't be changed when finished?

The java code will of course be compiled once, it's only the fxml files. The application now takes 25 seconds to start, with 14 seconds loading the fxml.

Is there a way to make all this faster?

EDIT #1:

Are there any tools that are provided for free and that make the execution of applications (Java) much faster? Or is the execution time merely dependent on the way the program is written?

Which design patterns could help fastening up the execution time of your application?

EDIT #2:

The following code will explain my problem in a nutshell:

package main;

.......
.......

public class MainClass {

    ....
    ....

    List<InformationController> controllerList;

    public mainClass(List<InformationControllers> controllerList) {
        this.controllerList = otherClass.getControllerList();
        loadFXMLFiles();
    }

    public void loadFXMLFiles() {
        for(InformationController controller : controllerList) {
            controller.loadFXML();
        }
        doOtherStuff();
    }

    ....

}

All those InformationControllers have their loading of other fxml files too, so it's actually a tree of fxml files that is loaded. This is loaded at every start of the application, so is there a way to do this loading only once maybe?

n00b1990
  • 1,189
  • 5
  • 17
  • 25
  • There are ways to make it faster. Can you post a [mcve](http://stackoverflow.com/help/mcve)? – jewelsea Jun 06 '14 at 08:43
  • I really would like to, but it's a closed source application and it's prohibited for me to post the corresponding code, or even a part of it, online. Is there maybe another way in which I can provide more information? And thanks for the help. – n00b1990 Jun 06 '14 at 08:46
  • You don't have to provide source of your application, you only need provide source (a *minimal* fxml file) which demonstrates the issue so that somebody else can reproduce it. Also check the [on-topic](http://stackoverflow.com/help/on-topic) list. – jewelsea Jun 06 '14 at 08:48

2 Answers2

20

On How to Speed up FXML Performance

I'll make this answer community wiki, if anybody else has further ideas, please edit it and add them.

  1. One should NOT use the static FXMLLoader.load() but should instead create an instance of FXMLLoader and reuse that one using the instance loader.load() method. The reason is that the FXML-Loader caches, e.g. class lookups, and hence is faster on loading the next FXML-File.
  2. Use a tool to compile the FXML to Java, such as Tom Schindl's FXML compiler or the NetBeans FXML to Java converter.
  3. Don't load any more FXML than you need to at any given time, e.g. if you aren't going to be displaying it right now, don't load it.
  4. Load the FXML in a background thread (doesn't work for some control types, e.g. Tooltip, in Java 8).
  5. Load an initial login or splash screen first and then load the rest of the FXML while the splash or login screen is displayed. I load FXML in some apps after the credentials are accepted at the login screen.
  6. Reduce the complexity of your application UI by removing unnecessary nodes.
  7. Ensure you aren't doing unnecessary work (e.g. reading a database) on the JavaFX UI thread in the initialize methods of your controllers.
  8. The FXMLLoader.load() documentation in JavaFX 8 includes a reference to FXML templates, but I don't think that was ever implemented, so maybe it won't help you.
  9. I heard mention that referring to static methods from FXML is slow.
  10. Use the latest development version of JavaFX.
  11. Once you have loaded a node hierarchy from FXML, reuse the hierarchy later rather than throwing it away and loading a new one (e.g. if you have a dialog window with contents constructed using FXML, when the user closes the dialog, just hide it and when you need to show a similar dialog again, just show the hidden dialog rather than constructing a whole new dialog and scene graph).

Reflection is why FXML is Slow

I think the key reason the Java 8 FXML implementation is slow is that it relies so heavily on reflection and reflection is slow as described in the reflection tutorial:

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

Community
  • 1
  • 1
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • 2
    one important point you forgot and might add is that one should NOT use the static FXMLLoader.load() but create an instance of FXMLLoader and reuse that one. The reason is that the FXML-Loader caches e.g. class lookups and hence is faster on loading the next FXML-File – tomsontom Jun 06 '14 at 09:41
  • 5
    This doesn't work. You can't reuse the same instance of FXMLLoader to reload different, or even the same document. Youwill get all sort of errors, like duplicate fx:ids, root is already set, and so on. It is not meant to be used that way. – olivierr91 Oct 19 '16 at 14:16
  • 2
    Yes, FXMLLoader is not meant to be reused. But you can, by `setRoot(null)` and `setController(null)` before you load. However, the claim that it's faster because it uses cache is still *wrong* because the cache is evicted before every load operation (see `clearImports()`) – Michel Jung Dec 15 '16 at 19:02
  • 2
    Just from curiosity (wanted to see if a single controller reference can be kept) i tried it, and it seems that a FXML Loader can be reused. The Loader, Parent and Scene can be declared as class fields (e.g myLoader etc). Then, inside a null check, an one - time initialization is made on first run. The instances then can be used every time with a new Stage. Can't say what is it good for. – Helmwag Apr 15 '17 at 15:55
  • @Jewelsea can you state with authority that re-using FXML loaders increases performance? I'm trapped by legacy and I need better performance. What about minifying the FXML before processing? I'm also considering a custom-URL scheme that would invoke a handler that uses a cache. Are there any other (least suprising) steps I can take to speed up FXML loading (--especially loading the same ~small file 100 times)? Going forward I'm using [tornadofx](https://tornadofx.io/). – Groostav Nov 07 '19 at 21:51
2

These are all great ways to improve performance. However if your issue is that it is running faster in Eclipse and then after compile you see a major slowdown in load times there is a much simpler solution.

For my project I was creating an embedded FX Browser inside an existing swing application. It worked fine in the IDE and loaded almost instantaneously, however upon compiling to a runnable jar, the runnable jar took a very long time to load the FX portion.

The solution to this was during the export to jar to select "Extract required libraries into generated JAR" instead of "Package required libraries into generated JAR". This will significantly speed up load times for any dependencies.

Chris Toh
  • 88
  • 1
  • 11