Today I am writing about the second tip to increase performance of JavaFX Mobile applications. I think this and the previous tip are the most important ones.
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 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.