Simplified 'Display' management for J2ME

Switching between displayable objects such as canvases and alerts can become tricky when working on more complex applications. Code can easily become cluttered with excess “display” and “midlet” references, despite that there is usually only one unique display instance.

This mess can be cleaned up by creating some static helper methods which provide instant access to the display instance without the need to maintain either midlet or display references.

public final class DisplayManager {

    // The one and only display object.
    private static Display display;

    // Get the one and only display object.
    public static final Display getDisplay() { return display; }

    // A one off call is required to prepare the display manager.
    public static final void initialize(Display display) {
        current = (DisplayManager.display = display).getCurrent();
    }

}

Several utility methods can then allow for tidier source code.

public final class DisplayManager {
    ...

    // Get displayable object that is visible on the handset screen.
    public static final Displayable getVisible() {
        return display.getCurrent();
    }

    // Helper method for cleaner code that is usually inlined by the compiler.
    public static final void setCurrent(Displayable d) {
        display.setCurrent(current = d);
    }

}

Without some sort of custom mechanism it is also very difficult to determine what displayable object was last assigned.

I suspect that Display.getCurrent will instantly spring to mind, but that function does not necessarily retrieve the last display which was shown with a corresponding Display.setCurrent call. Here is a typical example. Let us assume that there are three displayable objects A, B and C, and that object A is already shown on the handset display.

public void test(Display display) {
    Displayable firstTest = display.getCurrent();
    display.setCurrent(B);
    display.setCurrent(C);
    Displayable secondTest = display.getCurrent();
}

The value of firstTest is a reference of displayable object A, as we may expect. However, after two display changes, the value of secondTest is still a reference to displayable object A. This is because the display will not usually be switched until a specific event is handled by the underlying J2ME framework.

A simple solution to this problem (if this is a problem for your requirements) is to create a helper class which keeps track of the last display change. With such a class it is easy to determine which displayable is currently visible to the user and which displayable was previously set.

public final class DisplayManager {
    ...

    // The current displayable that is either visible or will be soon.
    private static Displayable current;

    // Get displayable object that is visible on the handset screen.
    public static final Displayable getVisible() {
        return display.getCurrent();
    }

}

There is, however, a glitch with the setCurrent(Alert, Displayable) method because after an alert has been discarded, the underlying J2ME framework will automatically revert to the next specified display without updating our current reference. I overcame this problem by introducing a custom Alert class, along with an additional helper method in DisplayManager.

public final class DisplayManager {
    ...

    public static final void setCurrent(Alert d, Displayable nextDisplayable) {
        // Place reference to next displayable object inside custom alert object.
        d.next = nextDisplayable;
        // Switch display using the new 'setCurrent' method.
        setCurrent(d);
    }

}

The custom Alert class can be used in exactly the same way as the regular Alert class. This version is able to automatically update the display manager. There are also several utility methods which make alerts far easier to use:

public class Alert extends javax.microedition.lcdui.Alert implements CommandListener {

    // Reference to next displayable object, made protected so that the display
    // manager is able to adjust it.
    protected Displayable next;

    // Standard constructors.
    public Alert(String title) {
        super(title);
        setTimeout(Alert.FOREVER);
        setCommandListener(this);
    }

    public Alert(String title, String alertText, Image alertImage, AlertType alertType) {
        super(title, alertText, alertImage, alertType);
        setTimeout(Alert.FOREVER);
        setCommandListener(this);
    }

    // Additional constructor for simplicity.
    public Alert(String title, String alertText, AlertType alertType) {
        super(title, alertText, null, alertType);
        setTimeout(Alert.FOREVER);
        setCommandListener(this);
    }

    // Default command listener will update display manager upon close.
    // A custom command listener can either clear or restore the next
    // displayable object manually.
    public void commandAction(Command c, Displayable d) {
        if (c == DISMISS_COMMAND)
            showNextDisplayable();
    }

    // Helper show methods.
    public void show() {
        DisplayManager.setCurrent(this);
    }

    public void show(Displayable nextDisplayable) {
        DisplayManager.setCurrent(this, nextDisplayable);
    }

    public final void showNextDisplayable() {
        if (next != null) {
        DisplayManager.setCurrent(next);
        next = null;
        }
    }

    public final Displayable getNextDisplayable() {
        return next;
    }

    public final void clearNextDisplayable() {
        next = null;
    }

}

In order for this to work, the display manager must be initialized when your MIDlet is first initialized. Simply adding the following line at the start of your MIDlet constructor should be sufficient:

DisplayManager.initialize(Display.getDisplay(this));

An alert can then be shown as shown below; please make sure that you use the Alert class from your namespace, or alternatively give your class a different name such as MyAlert.

// Display alert message.
new Alert("Greeting", "Hello World!", AlertType.INFO).show(this);
// Get current displayable object (The alert object).
Displayable current = DisplayManager.getCurrent();
// Get visible displayable object (The A object).
Displayable visible = DisplayManager.getVisible();