|
At KSPTech, a team of JavaFX developers spent over a couple of months developing Indaba Music's User Interface using JavaFX. What we learned during the development period was that subtle changes to your code can have huge impact on the performance of a JavaFX application. By making one or more of the following changes, we were able to improve user experience in a big way. Many of you may already be aware of certain performance pitfalls like Binding. In this blog, I'll try to cover as many tips as I can, over the next few days. Tip 1: def Instead of var This is the simplest one and the most obvious one. Whenever value of a variable is not going to change, it makes sense to define it as constant using the def keyword instead of var Keyword. Tip 2: Scope of a def/ var This may sound very simple and obvious. However, many of us define variables in a larger scope than required. This could result into performance hits as well. Scope of a def/ var should be as narrow as possible. Also, local variable are resolved differently than public variables. Reason being a variable in some other class may in future bind to a public variable. As a result, public variables pay a little penalty as compared to local variables. Tip 3: Avoid Duplication Writing a tight code is always advantageous. At any cost you should avoid duplicating efforts. For example, for a simple looking Image block below, there is lot happening behind the scene. Any duplication will result into duplication of all those actions | Source Code | def img = Image {
url: "<path to Image>";
} |
When the Image is created, it invokes the following actions: - Loading a file
- Allocating memory for the raster image
- Decoding the image into the raster format
Depending on the size and location of the image, creating extra copies of the image might significantly diminish your application performance. If the same image is used multiple times, create a single Image object and reuse it in different ImageView instances as shown in the following code.
| Source Code | def img = Image { url: "<path to image>";
for (i in [1..n]) ImageView { image: img } |
Tip 4: Script def / var
This builds on Tip 3. If a var or def is common to every instance of a class, it should better be declared as a script def/var. This has huge huge impact on performance. Specifically, if you are using the same image or imageview for all the instances of a class, it will not have to reload an image or peep into cache if it is cache. Source Code
| def img = Image { url: "<path to image>"; } def imageView = ImageView { image: img } class myNode extends CustomNode { ... init { scene = Group { content : [ ... imageView, ] } } } |
Tip 5 Turning Off Antialiasing Antialiasing is a technique used for smoothing the edges of curved lines (or text) and eliminating distortions of graphical objects to improve the visual appeal of the interface. In JavaFX, antialiasing is applied by default to all graphical shapes. However, the use of antialiasing slows performance. To avoid performance hits, you should turn off antialiasing unless it is really needed. For example, you do not need to apply antialiasing for rectangles unless they are transformed. Source Code
| public var group : Group = Group { content: ... clip: bind Rectangle { ... smooth: false; } |
Tip 6 Turning Off Caching of Images In JavaFX, shapes and images are cached by default. However, the images do not need to be cached. To have better performance and memory utilization, caching of images should be turned off.
| Source Code | def img = Image { url: "<path to image>"; } def imageView = ImageView { image: img; cache: false; } |
Tip 7 Replace bind with on replace
The keyword bind is incredibly powerful.
Source Code
| var a = bind y; var b = bind y; var c = bind y;
|
Whenever y changes, it triggers event and sets a, b and c to the updated value of y. However, nothing comes as free lunch. So did bind. In the above example, it will trigger three different events. It has high performance penalty. In my experience bind should be avoided at all cost for any real application.
Instead, there is another powerful aspect of JavaFX script: on replace. It is very similar to bind, however, it calls a block of code, instead, whenever y value changes.
Source Code
| var a: Number; var b: Number; var c: Number; var y: Number on replace { a = y; b = y; c = y; }
|
|