Skip Headers
Lightweight UI Toolkit Developer's Guide
Release 1.5
E23376-03
  Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

15 Portability and Performance

While portability is one of LWUIT's best attributes, it is also one of the hardest features to grasp. LWUIT is portable as a library and it also enables application porting in such a way that binary code or source can be compatible across different Java ME profiles.

Introduction

Much has been said in the past about Java device fragmentation (write once debug everywhere). To understand LWUIT's portability you must first understand the original problems and the solutions LWUIT provides for each problem:

Performance

Performance is a huge problem in portability. Problems in performance often creep on an application only to appear later in its life cycle. Performance is often a trade-off, mostly of memory for CPU or visa versa. The easiest way to improve performance is to reduce functionality.

Since LWUIT has pluggable theming you can substitute a simple theme without changing code. This makes it easier to see whether the problem is in the UI itself.

The following subsections discuss the specifics of memory and responsiveness. One thing to keep in mind is that performance and memory use on an emulator is no indication of device performance and memory overhead.

Memory

This section discussions factors that impact memory and speed.

Encoded Images

Memory is problematic, especially when programming small devices. When using LWUIT you must understand how memory directly relates to resolution and bit depth.

Assume you have two devices, a 16-bit color (65536 colors) device with 128x128 resolution that has 2 megabytes of memory, and a 24-bit color device (1.6 million colors) with a 320x240 resolution and 3 megabytes of memory. Which device provides more memory for a LWUIT application? The answer is not so simple.

Assume both devices have a background image set and scaled, so they need enough RAM to hold the uncompressed image in memory.

The smaller device needs 32,768 bytes just for a background buffer of the screen. The larger device requires 307,200 bytes for the same buffer!

Because screen buffers are needed both for the current form, the current transition (twice), and the MIDP implementation, the amount of memory the larger device consumes is staggering! How did we reach these numbers?

The simple formula is:

screen width * screen height * bytes per pixel = memory

Therefore:

16 bit: 128 * 128 * 2 = 32,768

24 bit: 320 * 240 * 4 = 307,200

Notice that in the 24-bit device 24 bits are counted as an integer because there is no 24-bit primitive and implementations treat 24-bit color as 32-bit color.

So getting back to the two devices: In the worst case scenario four buffers are immediately consumed, and the remaining RAM compares as follows:

16 bit: 2,097,152 – 32,768 * 4 = 1,966,125

24 bit: 3,145,728 – 307,200 * 4 = 1,916,928

It turns out the 24-bit device has more RAM to begin with but doesn't have as much RAM to work with!


Note:

All of these calculations don't take into account the additional memory overhead required for LWUIT and your application.


Thankfully, LWUIT offers a partial solution in the form of encoded images, which allow the device to cleanup unnecessary bitmap data from memory when it is scarce.

Encoded images work by using a weak/soft reference to a keep the encoded version of an image. For example, a PNG or JPEG is usually compressed at a very high ratio producing a much smaller byte size than the ones mentioned above (typically a 240x320 image can be 4-5kb or even less!). The EncodedImage keeps in memory the actual JPEG or PNG data, when image information such as pixels, dimensions etc. is needed the native Image object is dynamically created and maintained in a weak/soft reference for caching.

This allows the garbage collection to remove the image from memory when additional memory is needed, however its potentially expensive since an image might be created multiple times. It is also expensive to scale an encoded image since scaling is far more expensive for these cases.

The encoded image is the default image type returned when loading an image through a resource file.

Using encoded images, a UI-heavy application can be run on a 2 megabyte 320x240 24-bit color device. Note that using tiled images or a solid color to fill the background is much “cheaper” than the savings reachable using encoded images.

Speed

UI speed is often a user perception rather than a “real” performance issue. Slow performance happens, but a developer's opinion of performance may not match an end-user's perception. The best way to measure the speed of a UI is to give devices to a focus group of objective people and ask them how the UI “feels”.

That said, the following subsections you can monitor the event dispatch thread and LWUIT performance.

Event Dispatch Thread (EDT)

Performance often suffers because of slow paints. This often occurs when the EDT is being used without being released. It's important not to “hold” the EDT and release it immediately when performing long running tasks. For further details on releasing the EDT see Display methods callSerially, callSeriallyAndWait, and invokeAndBlock.

The EDT might be blocked due to unrelated work on a different thread. Bad thread scheduling on devices causes this problem, in part because many hardware devices ignore thread priorities.

On some devices networking can cause a visible stall in the UI, a problem for which there is no “real” solution. The workaround for such cases is logical rather than technical. In this case a standard progress indicator stalls during a networking operation. It might work better to use a progress indicator heuristic that moves slower or does not move at all so the user is less likely to notice the interruption in the display.

LWUIT Performance

Different transition types have different performance overheads on devices. Play with the transition selection and possibly disable transitions if necessary.

Indexed images carry a performance overhead. It shouldn't be excessive, but when using many animations or indexed images you can expect a slower repaint cycle, especially on devices without a JIT or fast CPU.

Light mode often trades speed for memory overhead. If there is plenty of memory and low performance, explicitly turning off light mode (after Display.init()) might impact speed.

Device Bugs And Limitations

This section describes the device bugs and limitations the LWUIT development team found while in the process of creating demos and applications. While this is not an exhaustive list, you can apply these principles if you encounter device issues of your own.

Bugs

The LWUIT development team encountered several device bugs and limitations (but not nearly as many as were expected). The first rule of bug investigation is:

It is not a VM bug.

Often developers blame the VM for bugs. Despite many rumors, the development team hasn't found a CLDC 1.1 VM with a significant bug (they reproduced crashes, but they were all due to bad API implementations).

The VM and GC seem to work pretty flawlessly, which means several things should work. You should be able to rely on proper exception handling and proper class loading behavior. This essentially allows you to use Java technology for exception handling and class loading to work with multiple devices, instead of the “problematic” preprocessor statements used in the past.

The preprocessor approach was essential in the past when targeting all phones (even seriously broken VMs) with code size requirements that were very low. Today's market has changed considerably, both in the quality of the common devices and in the space or OTA code size available for a typical application.

The advantages of avoiding preprocessor are mostly in code maintenance (refactoring, compiler checks, etcetera), simplicity in reusing object oriented paradigms, and easier deployment (one JAR file for all or most devices).

Rather than beat around the bush, here are a few examples of actual device behaviors:

  • A device throws an exception in a certain condition when using an API. This happens with several devices that fail in drawRGB. The solution is to catch the exception and activate a flag to invoke a different code path designed for that device class only.

  • Some devices have a bug with API X or with a specific usage of API X. Avoid that API or usage if possible. For example, many devices have a problem with flushGraphics(int, int, int, int), but all devices tested worked perfectly with flushGraphics().

As you can see, you can rely on Java working properly and throwing exceptions, making it possible to implement workarounds on the fly.

Limitations

The rules for dealing with device limitations are very similar to the rules for dealing with device bugs. If a missing API is invoked in code, it throws an exception because it doesn't exist. You can catch that exception and activate a flag disabling the functionality related to the feature. For example, your application might offer a location based feature based on JSR 179. You can wrap the calls related to JSR 179 code in try/catch and disable the functionality if a Throwable is thrown by the code (for example, NoSuchMethodError or ClassNotFoundException).

An example of this approach exists in the M3G class from LWUIT which is designed to run on devices that do not support JSR 184. The Log class is also designed in a similar way. It can utilize the FileConnector when the API is available in order to log to the device file system rather than RMS.

Limitations are often related to appearance, number of colors, device speed, device resolution, and so forth. These can be worked around using a multitude of themes and picking the right default theme upon startup. Use the methods in Display to check general device capabilities, then enable or disable some features.

For example, some devices support only three alpha levels (0%, 50%, 100%). This causes anti-aliased fonts to look horrible on those devices especially when using white over black color schemes. Devices like these can be easily detected using Display.numAlphaLevels() and such themes can be disabled on these devices (or simply excluded from the default state). Similar properties such as numColors are available on display.

Speed and memory constraints are much harder to detect on the fly. TotalMemory is often incorrect on devices and speed is notoriously hard to detect. True memory heap can be detected by allocating byte arrays until an OutOfMemoryError is thrown. While the VM is not guaranteed to be stable after an OOM it generally recovers nicely. Store the amount of memory in RMS to avoid the need to repeat this exercise.

The best solution is to allow your users as much configurability as possible (to themes, animations, transitions, etcetera) thus giving them the choice to tailor the application to their device needs.

Resolution Independence

One of the biggest problems in Java ME programming is the selection of device resolutions. This problem is aggravated by lack of scaling support and the small selection of devices with SVG device. A bigger problem than multiple resolutions is the problem of varying aspect ratios, even changing in runtime on the same device! (For example some slider devices change resolution and aspect ratio on the fly.)

LWUIT solves the lack of scaling support by including a fast low overhead scaling algorithm that keeps the image's alpha channel intact. Scaling on devices is far from ideal for some image types. It is recommended that designers avoid “fine details” in images that are destined for scaling.

Since images and themes can be stored in resource bundles, such bundles can be conditionally used to support different resolutions. This solution is not practical on a grand scale with a single JAR file strategy, however, for some basic resolution and important images this is a very practical solution, especially when dynamically downloading resources from a server.

Input

This section describes input methods that LWUIT supports.

Soft Buttons

Soft buttons for common devices in the market are detected automatically by LWUIT. If LWUIT fails to detect a specific device a developer can still set the key code for the soft keys using setter methods in Display.

LWUIT supports 3 SoftButton navigation common in newer phones from Sony Ericsson and Nokia. The 3 SoftButton mode can be activated via the Display class. In this mode the center “fire” key acts as a soft button.

Back Button

Some devices, most commonly older Sony Ericsson devices, have a special hardcoded back button device. You can assign a command as a “back command” using the form method for determining the back command. This ensures that only one command at any given time is deemed as a back command. The back command can also be configured using the Display methods. Currently the back button is only supported on Sony Ericsson devices.

Touch Screen Devices

Touch screens are supported out of the box, however, designing a UI for finger operation is very different from designing a UI for general use. Finger operations expect everything to be accessible via taps (not keys).

A touch interface expects widgets to be big enough to fit the size of a human finger. This is somewhat counter-intuitive because normally you might want to cram as much UI detail as possible into a single screen to avoid scrolling.

Component sizes can be easily customized globally using the theme. Simply set the default padding attribute to a large enough value (e.g. 5, 5, 5, 5) and all widgets “grow” to suit finger navigation. It is also a good practice to use buttons for touch devices and avoid menus where possible.

The only problem is that currently there is no standard code that allows you to detect touch screen devices on the fly. However such information can be easily placed in the Java application descriptor (JAD) file for the application to query.

Specific Device Issues

This list is rather limited since the development team doesn't have much to say about most devices. Most of the common CLDC 1.1 devices just work out of the box without much of a hassle. This section describes behaviors that might catch developers off guard. This is by no means an exhaustive or definitive list.

Motorola

The RAZR family doesn't support different levels of translucency -only 50% translucency is supported. This causes anti-aliased fonts to look bad on these devices.

Create a .cod File

  1. Create a new project in JDE and name it appropriately. Select project type: "Empty Midlet project".

  2. Right click on the project and choose the "add file to project" option and choose the JAR file from your projects /dist directory.

  3. Right click on the project and choose "properties".

  4. In the "Application" tab insert the name of your main MIDlet class.

  5. Build and run the project.

Nokia S40

Generally series 40 devices work well. Some “high end” S40 devices only contain 2mb of memory yet have 24-bit color 320x240 resolutions. These devices have 3mb installed but only 2mb is accessible to Java applications.

The Nokia S40 emulator provides a very good approximation of the devices.

Sony Ericsson

Sony Ericsson makes good Java devices that are indexed with memory and have 16-bit color for even better memory.

The Back button, as discussed in Back Button exists in SE until JP-8, at which point a new interface based on three soft keys was introduced.

Native Networking Sony Ericsson threads in SE tend to freeze the GUI. The devices in JP-7 and newer completely ignore thread priorities as well.

General Portability Tip

Test on manufacturers emulators. While development is easier using the Java ME SDK, the Sprint Plugin for Java ME SDK, or the Sprint Wireless Toolkit, there is no substitute for occasional emulator testing. An emulator provides more accurate memory readings especially related to images and buffers.