|C H A P T E R 16|
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.
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:
This problem was far more severe with older (prior to CLDC 1.1) devices that LWUIT does not support. Thanks to modern TCKs, the virtual machine (VM) in modern devices is compatible, and furthermore the UI layer on which LWUIT is based is very narrow and relatively robust across devices.
Again with newer CLDC 1.1 devices this is not as much of a problem as it used to be, but there are still concerns. See Chapter 2 for a discussion on increasing performance and reducing memory overhead (sometimes trading off one for the other).
LWUIT ships with a very fast low memory overhead scaling algorithm that doesn't lose transparency information. For extreme cases where the algorithm is not enough, LWUIT supports pluggable themes, allowing the UI to be customized with images more fitting to the resolution of the phone.
LWUIT detects soft buttons automatically, and navigation is already portable. LWUIT supports touch screens seamlessly out of the box. Text input works with the device native text box, ensuring proper input.
This problem is solving itself, given relaxed carrier restrictions and increasing JAR file size allocations. LWUIT fully supports obfuscation and works properly with obfuscators that remove redundant code.
LWUIT currently focuses only on UI related issues, so you must find your own solution for the many minor issues related to these problems. For most common use cases failure occurs because the device expects the “right thing”. For example, networking is problematic on some devices due to a connection that was never closed, and so forth.
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.
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.
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.
Indexed images perform this magic by storing images as byte arrays with a lookup table. They trade off memory overhead for drawing performance, but in general on‐device performance is good. Another drawback of indexed images is a restriction to no more than 256 colors per indexed image.
Using indexed 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 even “cheaper” than the savings reachable using indexed images.
Some of the default settings in LWUIT are memory intensive because LWUIT is designed for higher memory devices. However, LWUIT has a special flag to accommodate low memory devices and it can be activated in Display. Display's init() method initializes the flag to a sensible default value which affects the way bitmap fonts and other LWUIT features utilize memory.
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”.
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.
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.
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.
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.
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).
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().
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.
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.
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.
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 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.
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.
Since the BlackBerry doesn't have soft keys they are mapped to the Q/W and P/O keyboard keys. In order to build a release for the BlackBerry a COD file must be produced with the BlackBerry Java Development Environment (JDE), otherwise the MIDlet JAR file size is too big for the BlackBerry device.
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 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.
Test on manufacturers emulators. While development is easier using the Sun Java Wireless Toolkit and Sprint Wireless Toolkit, there is no substitute for occasional emulator test. An emulator provides more accurate memory readings especially related to images and buffers.