Best Practices for JavaFX Mobile Applications

As everybody who is interested in JavaFX will know by now, JavaFX Mobile was released a short while
ago. It was a hell of a ride, that’s for sure. I felt so exhausted, I did not even have the energy to blog during the release…

But by now I feel recovered and want to start a little series about lessons we have learned while preparing the release and give some hints how to improve the performance of JavaFX Mobile applications.

WARNING: The tips I am giving here are true for the current version of JavaFX Mobile, which is part of the JavaFX 1.1 SDK. In future versions the behavior will change, the
current bad performance of the mentioned artifacts will be optimized away or at least significantly improved. Everything I am writing about here is a snap-shot, nothing should be understood as
final!

Item 1: Avoid unnecessary bindings

Bindings are very convenient, without any doubt one of the most valuable innovations in JavaFX Script. Unfortunately they come with a price. The generated boiler-plate code is usually not as small and
fast as a manual implementation would be. Especially complex dependency-structures tend to impose a severe penalty on performance and footprint.

For this reason it is recommended to avoid bindings as much as possible. Often the same functionality can be implemented with triggers. One should not use bindings to avoid the hassle of dealing with the initialization order. And it certainly makes no sense to bind to a constant value.

Lazy bindings are most of the time (but not always!) faster if a bound variable is updated more often then read, but they are still not as fast as manual implementations.

Example

A common use-case is a number of nodes which positions and sizes depend on the stage-size. A typical implementation uses bindings to achieve that.

Here we will look at a simple example, which resembles such a situation. The scene consists of three rectangles which are laid out diagonally from the top-left to the bottom-right. The size of the rectangle is a quarter of the screen-size. Code Sample 1 shows an implementation with bindings.

 1 def rectangleWidth: Number = bind stage.width * 0.25;
 2 def rectangleHeight: Number = bind stage.height * 0.25;
 3
 4 def stage: Stage = Stage {
 5     scene: Scene {
 6         content: for (i in [0..2])
 7             Rectangle {
 8                 x: bind stage.width * (0.125 + 0.25*i)
 9                 y: bind stage.height * (0.125 + 0.25*i)
10                 width: bind rectangleWidth
11                 height: bind rectangleHeight
12             }
13     }
14 }

Code Sample 1: Layout calculated with bindings

The first question one should think about is wether the bindings are really necessary. On a real device the screen-size changes only when the screen orientation is switched (provided that the device supports this functionality). If our application does not support screen rotation, the layout can be defined constant.

One possible solution to reduce the number of bindings is shown in Code Sample 2. Two variables width and height are introduced and bound to stage.width and stage.height respectively. Their only purpose is to provide triggers for stage.width and stage.height, since we do not want to override the original triggers. Position and size of the rectangles are calculated manually in the triggers.

 1 def r = for (i in [0..2]) Rectangle {}
 2
 3 def stage = Stage {
 4     scene: Scene {content: r}
 5 }
 6
 7 def height = bind stage.height on replace {
 8     def rectangleHeight = height * 0.25;
 9     for (i in [0..2]) {
10         r[i].height = rectangleHeight;
11         r[i].y = height * (0.125 + 0.25*i)
12     }
13 }
14
15 def width = bind stage.width on replace {
16     def rectangleWidth = width * 0.25;
17     for (i in [0..2]) {
18         r[i].width = rectangleWidth;
19         r[i].x = width * (0.125 + 0.25*i)
20     }
21 }

Code Sample 2: Layout calculated in trigger

Without any doubt, the code in Code Sample 1 is more elegant. But measuring the performance of both snippets in the emulator, it turned out the code in Code Sample 2 is almost twice as fast.

9 responses to “Best Practices for JavaFX Mobile Applications”

  1. Vaibhav Choudhary Avatar

    Item 1 is completely true. We are so used to binding that we put bind before every line.

  2. Mike Avatar
    Mike

    Yeah, but I think ultimately, the best desirable solution is to have the compiler be smart enough to optimize out the binding cases so that the developer wouldn’t have to worry about extraneous, unnecessary bindings. Kind of like what HotSpot does now with loops and the inlining stuff. Binding is such a core concept to JavaFX that I would really hate to be self conscious about using it.

  3. Philippe Lhoste Avatar

    "And it certainly makes no sense to bind to a constant value."

    Aha! I was puzzled to see sometime
    someProperty: bind "SomeString"
    I am happy to see confirmation that it is useless!

    I suppose in the future the compiler will not generate binding for these expressions (or a warning, which could be better, as a way to better code writing…).

    Interesting trick, for sure. Thanks.

  4. Michael Avatar

    Hello, how do you post code parts in blogs messages?

  5. Michael Heinrichs Avatar
    Michael Heinrichs

    I am using NetBeans to generate the html-code. The functionality is called "Print to HTML" there. You just have to define the style in your CSS-file to get the syntax highlighting.

  6. rob Avatar
    rob

    Thx for the tips…were really helpful in my project of developing an application to take part in Nokia’s Calling All Innovators, 2009 contest. Will be back with more when I make some more progress.

  7. caswi Avatar
    caswi

    A better way is to bind height and width on scene.height and scene.width
    => Window decorations will not affect calculation

    var r = for (i in [0..2]) Rectangle {}
    var scene = Scene {content: r}
    var stage = Stage {
    height: 260
    width: 260
    scene: scene
    }

    var height = bind scene.height on replace {
    var rectangleHeight = height/3;
    for (i in [0..2]) {
    r[i].height = rectangleHeight;
    r[i].y = height/3*i;
    }
    }

    var width = bind scene.width on replace {
    var rectangleWidth = width/3;
    for (i in [0..2]) {
    r[i].width = rectangleWidth;
    r[i].x = width/3*i
    }
    }

  8. kamil Avatar
    kamil

    please help i don’t go to java document

  9. guy vo Avatar
    guy vo

    hi Micheal,

    Great you blogged on the subject !

    I encountered also a huge performance issue on mobile 6.1 with early access on my HTC. True I use a lot of binds (really needed to decouple the view with the model) and the screen counts 24 shapes 24 buttons which are bind to my model objects in. All instantiated in the beginning of the app.

    It takes 1 min 30 seconds to launch the app ! ( on my iMac it’s less than 1 second ) Once started it works kind smoothly could be better but considering it’s only a mobile with single core and less fast on speed it works well. An other example is a creation at runtime if customnode with 2 shapes, 3 Textboxes and a button also with some binding takes 5 seconds ! The latter is a real DON’T LIKE.

    So apparently the instantiations of controls with lots of binds takes a huge charge for the mobile VM. For the moment the best thing you can do if you have still some binds in your app is trying to creating them all ( sequence of nodes ) in the start up of the app and later on, switch or assign them to the scene view dynamically with your customized views or nodes.

    My point here is optimizing useless binds yes, but for useful and needed binds to have the MVC pattern implemented as much as possible I say that there is still a lot of work to do in finding an increase of performance ( say factor 10 ) on the mobile platform.

    I don’t know if there are any benchmarks available but if so I would like to post some results there too.

    I hope that the next version of javaFX mobile will have some optimizations especially on performance. I don’t know if window mobile 6.5 will bring me some boost but I doubt it really.

    Guy