Alper Celik

Best Practices for JavaFX Mobile Applications

Note: it was originally posted by Mike


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.

Item 2: Keep the scenegraph as small as possible

Behind the scenes of the runtime a lot of communication takes place to update the variables of the nodes in a scenegraph. The more elements a scenegraph has, the more communication is required. Therefore it is critical to keep the scenegraph as small as possible. Especially animations tend to suffer from a large scenegraph.

It is bad practice to keep a node in the scenegraph at all times and control its visibility via the visible-flag or its opacity. Invisible nodes in the scenegraph are still part of the communication-circus in the background. Instead one should remove nodes from the scenegraph and add them only when required.

This approach has one drawback though. Adding or removing nodes takes longer than setting the visibility. Therefore it might not be appropriate in situations were immediate responses are critical.
Example 1

Often one has a set of nodes of which only one is visible. These can be for example different pages, or nodes to visualize different states of an element. One might be tempted to add all nodes to the scenegraph and set only the current as visible.

Code Sample 1 shows a simplified version of this approach. Three colored circles are created to visualize some kind of state (red, yellow, green). Only one node is visible at any time. (Let's ignore for a second that this could simply be achieved by changing the fill-color of a single circle. In real life applications one would probably have images or more complex shapes for visualizations and simply changing the color would not work.)

1 def colors = [Color.GREEN, Color.YELLOW, Color.RED];
2
3 var state: Integer;
4
5 Stage {
6 scene: Scene {
7 content: for (i in [0..2])
8 Circle {
9 centerX: 10
10 centerY: 10
11 radius: 10
12 fill: colors[i]
13 visible: bind state == i
14 }
15 }
16 }
Code Sample 1: Using visibility to switch between nodes

This results in three nodes in the scenegraph although only one is shown. This should be refactored to ensure that only the visible node is in the scenegraph. Code Sample 2 shows one possible implementation.

1 def colors = [Color.GREEN, Color.YELLOW, Color.RED];
2
3 var state: Integer on replace oldValue {
4 insert nodes[state] into stage.scene.content;
5 delete nodes[oldValue] from stage.scene.content;
6 }
7
8
9 def nodes = for (i in [0..2])
10 Circle {
11 centerX: 10
12 centerY: 10
13 radius: 10
14 fill: colors[i]
15 }
16
17 def stage = Stage {scene: Scene{}}
Code Sample 2: Adding and removing nodes when required

The code in Code Sample 1 is more compact, but Code Sample 2 reduced the number of nodes in the scenegraph from three to one. While tuning some of the demos for the JavaFX Mobile release, we were able to reduce the number of nodes in the scenegraph by 50% and more, simply by ensuring that only visible nodes are part of it.
Example 2

If nodes are shown and hidden with some kind of animation, adding and removing the node to the scenegraph becomes extremely simple. One only needs to implement an action at the beginning of the fadeIn-animation and at the end of the fadeOut-animation to add respectively remove the node. Code Sample 3 shows such a usage where a simple message-box is shown and hidden by changing the opacity.

1 def msgBox = Group {
2 opacity: 0.0
3 content: [
4 Rectangle {width: 150, height: 40, fill: Color.GREY},
5 Text {x: 20, y: 20, content: "Hello World!"}
6 ]
7 }
8
9 def fadeIn = Timeline {
10 keyFrames: [
11 KeyFrame {
12 action: function() {insert msgBox into stage.scene.content}
13 },
14 at (1s) {msgBox.opacity => 1.0 tween Interpolator.LINEAR}
15 ]
16 }
17
18 def fadeOut = Timeline {
19 keyFrames: KeyFrame {
20 time: 1s
21 values: msgBox.opacity => 0.0 tween Interpolator.LINEAR
22 action: function() {delete msgBox from stage.scene.content}
23 }
24 }
25
26 def stage = Stage {scene: Scene{}}
Code Sample 3: Using fadeIn- and fadeOut-animations to add and remove nodes.


Source: http://blogs.sun.com/javafx/entry/best_practices_for_javafx_mobile

Tags: applications, best, for, javafx, mobile, practices

Share 

Add a Comment

You need to be a member of Open Source University Meetup to add comments!

Join this social network

4 Comments

Alper Celik Comment by Alper Celik on March 5, 2009 at 7:25am
Thanks Peter,

This is a great video
Peter Miklosko Comment by Peter Miklosko on March 5, 2009 at 4:19am
This video tutorial looks good for beginners with some knowledge of Java
Peter Miklosko Comment by Peter Miklosko on March 4, 2009 at 4:40pm
Nice article, shame that this web site developers still did not implement and put in use for us anything to contain and properly display code samples like may programming forum does with use of code tags [code] or
Mesut Altinyaprak Comment by Mesut Altinyaprak on March 4, 2009 at 1:10pm
thanx alper :)it is nice

Webinars

OSUM members get exclusive access to a series of webinars on the most innovative open source technologies via the OSUM Webinar Series.

If you missed any of the previous OSUM Webinars, click here to listen to the replays of the previous sessions.

News

Download Free OpenOffice.org Guide For Creating Large Documents One of the advantages of OpenOffice.org is its ability to handle large word processing documents such as theses and research papers. Download this free guide now and read expert advice on writing with OpenOffice.org.

Get On Board with JavaFX & the Tech Train Game

Get a hands-on introduction to JavaFX when you play the Tech Test Train - Ride the train, test your knowledge of JavaFX technology, and earn points. Click HERE to play.

Working With ZFS Snapshots Download the free ZFS Snapshots How-To Guide to learn how to create and use the backup and restore capabilities of ZFS snapshots.

© 2009   Created by Gary Serda

Badge  |  Report an Issue  |  Privacy  |  Terms of Service