Best Practices for JavaFX Mobile Applications 4

The fourth part of my series about best practices for JavaFX Mobile Applications focuses on image loading.

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 5: Use the prescaling functionality

If an image needs to be scaled and the scaling factor does not change later, it is recommended to use the prescaling functionality. This can be done by setting width and height of an Image object, which will scale the image while it is loaded.

Using prescaling has two benefits. First of all it results in better performance. If prescaling is used, the scaling is definitely calculated only once. In contrast the scaling of an ImageView object is recalculated each time its transformation is changed by something else then a translation. For example changing the rotation will result in recalculating the scaling. Secondly, if an image is down scaled, memory usage is much smaller if prescaling is used.

Scaling can be calculated even faster if the flag Image.smooth is false. But the quality of the scaled image must be checked.

Example

This example generates thumbnails for a number of images. Code Example 1 creates a sequence of thumbnails, using the scaling functionality of ImageView.

1 def thumbnails = for (i in [0..11])
2     ImageView {
3         image: Image {url: "{__DIR__}images/img{i}.png"}
4         preserveRatio: true
5         fitWidth: 30
6         fitHeight: 20
7     }

Code Sample 1: Scaling within ImageView

The same can be achieved using the prescaling functionality of the Image class as shown in Code Example 2. Displaying the thumbnails is usually faster with this approach and the memory usage is much smaller.

1 def thumbnails = for (i in [0..11])
2     ImageView {
3         image: Image {
4             url: "{__DIR__}images/img{i}.png"
5             preserveRatio: true
6             width: 30
7             height: 20
8         }
9     }

Code Sample 2: Prescaling with Image

Item 6: Use background loading

The class Image provides a nice, but easily overlooked feature, to load images asynchronously in the background. This will not speed up the runtime performance or reduce the footprint of an application, but it can significantly improve startup time. To enable it, the flag Image.backgroundLoading must be set.

Background loading has two consequences, which need to be considered during implementation. If an image which is loaded in the background is supposed to be displayed shortly after creation, it is necessary to check the progress of the download. Otherwise an empty image will be shown first. Another option is to set the variable placeholder to display a substitute-image until the real image is finished loading. This approach is used in the example below.

The second consequence is, that width and height of an image are not set until the image is completely loaded. This will probably spoil any layout, which depends on the size of the used images. Again, a placeholder image can be used to overcome this, if placeholder-image and final image have the same size. Or width and height can be set manually, which would prescale the image to the given size. The last option is to recalculate the layout once the image is finished loading.

Example

Code Sample 3 extends the example from above to load the thumbnails in the background and displays them. While the images are loaded a placeholder (logo.png) is displayed, which has the same size as the thumbnails. Note that the logo is not loaded in the background to make sure we can display it immediately.

 1 def logo = Image {url: "{__DIR__}images/logo.png"}
 2
 3 def thumbnails = for (i in [0..11])
 4     ImageView {
 5         image: Image {
 6             url: "{__DIR__}images/img{i}.png"
 7             preserveRatio: true
 8             width: 30
 9             height: 20
10             backgroundLoading: true
11             placeholder: logo
12         }
13         x: i mod 4 * 50 + 20
14         y: ((i/4) as Integer) * 40 + 20
15 }
16
17 Stage {scene: Scene {content: thumbnails}}

Code Sample 3: Loading thumbnails in the background

On the emulator one has to look really close to notice the background loading. On a real device loading the images usually takes longer. With background loading enabled, the screen is displayed quickly, first showing only the placeholders, which are one after the other replaced with the real images. If background loading is disabled, the application would show a blank screen until all images are completely loaded and displayed.

Links to previous parts:

Item 1: Avoid unnecessary bindings
Item 2: Keep the scenegraph as small as possible
Item 3: Use simple shapes instead of images
Item 4: Use small images instead of complex shapes