Big designs for small devices

Four mobile design patterns simplify interactive content development

1 2 Page 2
Page 2 of 2

Listing 4. onLeave() implementation that checks for keywords

   public int onLeave( int dir )
      if ( dir == WDialog.FORWARD )
         // Question2 is a text box
         String answer = question2.getString();
         // Make sure user has entered 3 characters, and set the answer to a global variable
         if ( answer.length() < 3 )
            // Show an alert screen
            Alert alert = new Alert("Bad Inpt");
            alert.setString( "You must enter at least 3 characters for keyword" );
            super.engine.getDisplay().setCurrent( alert, this );
            return WDialog.REJECT;
         } else
            Wizardlet.answer2 = answer;
            return WDialog.OK;
      } else
         return OK;

The Wizard Dialog pattern allows developers to focus on their applications' user experience and screen flow, rather than on the wizard application's screen-by-screen wiring. Not only does Wizard Dialog save development time, it also reduces coding errors.

Pagination pattern

Mobile devices obviously have very limited screen real estate; they usually hold less than 10 lines of text. In many mobile applications, pagination is a hideous process. During pagination, large content pages break into multiple smaller pages; each contains a subset of the complete content. Users view the complete content by paging through the subset using a More or Next command.

In our restaurant search example, a wide search may result in 200 matches. This can divide into 10 pages, each page containing 20 matches in the list. Applications with pagination are more user friendly than those without because it takes less keystrokes to reach the target item. In some devices, pagination is also necessary for performance reasons. I have seen developers put 1,000 items in a single MIDP List, and the target phone consequently cannot respond to a single request. It takes a lot of memory and processing power to show 1,000 strings on a mobile phone.

The Pagination pattern provides a component that automates the paging process. This pattern also creates a clear separation between the data model and the view component. The data model in this case is the complete dataset (e.g., the 200 search matches). The data model does not need to know how the data breaks up to fit the display. The view component creates multiple content pages from the complete dataset. This is similar to a graphical user interface (GUI) toolkit (view) automatically providing a scroll bar to scroll a large image (the data) on a desktop application.

Figure 5. Pagination UML diagram

The Pagination pattern is a viewer-specific pattern that can be fully implemented in one class, PagableList. PagableList is a MIDP List subclass. Your application can treat this as an ordinary List class and perform usual List operations on it. You can add items and commands, and register command listeners. But it is not an ordinary List on the inside.

PagableList is a proxy to the original List because it overrides some of the methods. Internally, it holds the entire dataset and manages a sublist of it. It maintains a cursor that points to the currently displayed sublist index. It registers two built-in commands: the More and Previous commands. When users hit the More command, PagableList automatically advances to the next set of sublists and displays them on the screen. Similarly, when users hit the Previous command, PagableList rolls the cursor back to the previous dataset and puts them on the screen. By managing an internal cursor, users can quickly page through each data subset.

PagableList is a ready-to-use component. No additional work is required to enable pagination for your application. You simply create an instance of PagableList instead of a List and add data to it using the append() method. Since PagableList is a List subclass, it supports all List behavior, and you can cast its type into List throughout your application. This code fragment shows how to use PagableList:

Listing 5. PagableList sample usage

   PagableList pagablelist = new PagableList( "Paging", List.IMPLICIT);
   // 'this' refer to the current MIDlet
   for ( int i=0; i< 100; i++ )
      pagablelist.append( "Item  #"+i, null );

PagableList implements a proxy pattern. By encapsulating the original List from the outside, PagableList puts additional functionality on top of List. The original proxy pattern suggests encapsulation by using a placeholder to control access to the subject. I modify it to include encapsulation by subclassing and overriding the List's interface. This approach allows me to preserve List's interface and type hierarchy, making it easier to use and lowering this pattern's overhead. Small optimizations like this can greatly improve design pattern usage in constrained J2ME environments.

Slide Show pattern

A slide show is another common form of interactive content usually viewed on desktops. A slide show is a sequence of screens that displays in a specific order. Each slide contains texts, images, or a mixture of both. For this article's purpose, we only consider the autopilot-mode slide show. The sequence appears as it is programmed; users cannot control the sequence's pace or order. A pause occurs between each slide so users have enough time to view and read a slide's content. The application controls the slide show's start and stop. The slide show also stops when it reaches the end of the sequence. The slide show requires the ability to add and remove slides easily without impacting other slides already implemented. The dependency between slides must be minimal.

Figure 6. Example slide show sequence

Similar to the Wizard Dialog solution previously discussed, a mediator flexibly decouples related screens. A slide show application shares some similarities with a wizard application in that they both involve multiple screen displays. In this solution, we encapsulate all the slide show's behavior into one class: SlideEngine. The SlideEngine class is an execution engine of the slide show sequence. Each slide is an implementation of the MIDP Displayable class. For text slides, we use TextBox. For image slides, we use Form with ImageItems or a custom Canvas implementation. Since every slide must be set into the Display object to display on a device screen, SlideEngine also holds a reference to the current MIDlet Display object during initialization. A sequence is a series of alternating Displayable objects. A time interval representing each slide's display duration follows each Displayble object (slide). The longer the interval, the longer a slide stays before the next slide displays. Let's put all these requirements into a UML diagram.

Figure 7. Slide Show UML diagram

The sequence creation is simple: Add Displayable objects into SlideEngine. Create MIDP user interface (UI) components, such as Form and TextBox, in the usual way. Then add these objects to the sequence in SlideEngine using the addSlide() method. The addSlide() method takes two parameters: a Displayable object that represents the slide and an integer that represents the slide's duration (in milliseconds).

Listing 6. Slide show implementation

    // Create a slide show engine with Display object as parameter.
    // 'this' pointer refers to current MIDlet.
    engine = new SlideEngine( Display.getDisplay(this ) );
    // Create 3 slides. All the slides are formed here.
    // You can use something else.
    Form f1 = new Form( "Slide 1");
    f1.append( "This is slide number 1" );
    Form f2 = new Form( "Slide 2");
    f2.append( "This is slide number 2" );
    Form f3 = new Form( "Slide 3");
    f3.append( "This is slide number 3" );
    // Add the slides to engine, each slide stays on screen
    // for 2 seconds.
    engine.addSlide( f1, 2000 );
    engine.addSlide( f2, 2000 );
    engine.addSlide( f3, 2000 );
    // Start the slide show

The SlideEngine class serves as a mediator between each slide and the Display object. It is a reusable component. When the startShow() method starts SlideEngine, an internal thread is created and executes the sequence. This thread uses Display.setCurrent() to put a slide on screen and then sleeps for the slide's duration. The procedure repeats until it reaches the end of sequence or endShow() is called. When the sequence ends, the internal thread also terminates. Since the slides are decoupled and a separate yet reusable object (SlideEngine) handles execution, rearranging the slide or sequence has no impact on slide implementation. Each slide can be programmed individually and then joined with other slides.

Don't reinvent the wheel

Design patterns capture development experiences. A well-designed pattern is an effective way to share design knowledge among developers and build structured software. Design patterns, together with their implementations, increase productivity by encouraging developers to build highly maintainable and reusable software or components.

Creating design patterns for J2ME environments takes special consideration. Factors include code size and performance. Many design patterns provide flexible ways to build applications, but they often result in more classes (such as abstract classes) and more complex object hierarchies. However, you can modify design patterns to fit your needs—you might take away some flexibility, but the patterns will still be powerful enough to solve your problems in various scenarios. Your techniques will only improve with experience.

Keep in mind you can always mix and match several patterns in one application. A proper combination of several patterns often creates a more effective pattern. For example, you can use the Slide Show pattern with the Abstract Factory pattern to create a fully content-driven slide show application. There are endless design pattern possibilities. Never underestimate the power of patterns in J2ME environments.

Ben Hui has been programming with Java since its inception and has become addicted to consumer device technologies in recent years. Currently, Ben is a mobile technology specialist who develops software for PDAs and mobile devices and is keen on making J2ME technology work in harmony with daily life experiences.

Learn more about this topic

1 2 Page 2
Page 2 of 2