Big designs for small devices

Four J2ME design patterns simplify interactive content development

Java 2 Platform, Micro Edition (J2ME) Mobile Information Device Profile (MIDP) is undoubtedly the dominant mobile phone programming platform today. The number of J2ME-enabled phones and J2ME applications continues to rapidly grow. However, working with J2ME is often complex. This isn't because J2ME is a sophisticated platform, but because J2ME is a constrained platform. Although MIDP is popular for building interactive applications, such as games, on mobile devices, it frequently exposes its weakness and limitations. Creating simple interactive content with MIDP is often complicated and requires repetitive programming tasks. This consequently burdens many developers.

After working on several MIDP projects, I found that many recurring problems could be solved with well-defined design patterns. I chose several design patterns that fit my problem scenarios and then tailored those patterns to comply with J2ME platform constraints (especially application size and performance constraints).

In this article, I examine four design patterns and strategies to implement interactive content on mobile devices. Each pattern has its unique role in creating a maintainable and reusable framework. You can download the source code for these patterns from Resources.

To understand this article's material, you should be familiar with MIDP's building blocks such as MIDlets, Display, and high-level user interface components in the javax.microedition.lcdui package. Readers also need basic Unified Modeling Language (UML) knowledge to read the design diagrams. If you are unfamiliar with these technologies, now is a good time to get up to speed. Resources are provided below.

Cascading Menu pattern

Let's start with the most interesting pattern: Cascading Menu. A menu is a fundamental way to navigate an application on constrained devices. A cascading menu has a long history on older electronic devices such as digital organizers and legacy terminals. System functionalities are organized in a hierarchy of nested menu options. Figure 1 is an example of a cascading menu for a city guide application. When users select a menu option, it takes them to a submenu with another list of available options. Users continue to navigate down the menu system until they hit the menu hierarchy's end node, which usually instructs the system to perform a function (e.g., retrieve relevant data).

Figure 1. A city guide application using Cascading Menu

This user interface format is commonly found in Wireless Application Protocol (WAP)-based content. By defining each menu option as an anchor (or link), Wireless Markup Language (WML) makes Cascading Menu a very simple system to implement. However, this is not the case in the MIDP world.

If you use MIDP's high-level (yet very constrained) user interface components, you might choose to implement several List objects. Each List object implements a menu screen with an options list. Upon a selection event, a CommandListener, the controller, determines which menu option was selected and updates the screen with another List object that represents the submenu. This solution is viable when you have only two or three choices in your menu system. If you add more menu screens to the hierarchy (say, 10 menus), it becomes a complicated approach. You would need to create 10 different List subclasses (Menu1Class, Menu2Class, Menu3Class) for the corresponding menu screens. These menus are difficult to manage and maintain. The dispatching logic between menus becomes a complex network of menu options and screens.

Fortunately, we can create a reusable and maintainable menu system. Another popular pattern, the Model-View-Controller (MVC) pattern, can shed some light on this situation. The MVC pattern offers maintainable and reusable user interfaces by separating the responsibilities of the model, view, and controller. The model is a data structure that represents the content behind the user interface application. The view is a visual component that displays content and receives user input. The controller serves as a bridge between model and view by implementing the logic and workflow to update the model and view.

The Cascading Menu pattern is a scaled-down version of the MVC pattern. We identify the menu hierarchy as this formula's model. We must implement a view component that can adapt to an arbitrary complex data model and reflect the model's current state. In other words, we build and maintain the menu model independently from the view component. The view component renders the menu screens based on the current menu model. The view component updates the screens when the menu model updates. Any changes to the menu hierarchy will automatically modify the presentation. Rearranging the menu system is just a matter of updating the menu tree data model.

Figure 2. Cascading Menu UML diagram

Figure 2 is the Cascading Menu pattern's UML diagram. The MenuElement class is our data model implementation. We use MenuElement to create a menu tree structure. Each MenuElement instance represents a node in this tree, and there are two node types: parent nodes (or menu containers) and child nodes (or menu items). For example, Main Menu (in Figure 1) is a parent node (or menu container). Shops, Restaurants, and Attractions are the Main Menu's child nodes (or menu items). We establish this relationship using the addChild() method.

Listing 1 shows how Figure 1's menu hierarchy is built. Once the data model is created, we feed it into our view component, MenuList. MenuList is a subclass of MIDP List and is responsible for displaying menu items as a list. MenuList can be reused in many menu-based applications because its behavior is driven by the menu data model. The showMenu() method instructs MenuList to display the Main Menu. MenuElement handles navigation logic. When a menu item is selected, the current MenuElement determines the item's associated object during addChild(). If the associated object is another menu screen (i.e., another MenuElement object), it replaces the current menu with the later one using MenuList.showMenu().

A user will eventually reach a menu item that triggers some action. We can create this link by adding a MenuElement associated with a MDisplayable object. The interface method onDisplay() is called when a user selects that menu item. We can perform the necessary action with onDisplay(). Listing 2 shows an onDisplay() implementation.

Listing 1. Build a menu hierarchy with MenuElement

   // Create three menus.
   // Use MenuElement for a menu container and
   // use MenuElement also for menu item in the container.
   // Link each menu item to a sample Mdisplayable.
   MenuElement menu3 = new MenuElement( "Attractions" );
   menu3.addChild( new MenuElement( "Museum"), new SampleMenuAction() );
   menu3.addChild( new MenuElement( "Art Galleries"), new SampleMenuAction() );
   menu3.addChild( new MenuElement( "Exhibitions"), new SampleMenuAction() );
   
   MenuElement menu2 = new MenuElement( "Restaurants" );
   menu2.addChild( new MenuElement( "Bakeries"), new SampleMenuAction() );
   menu2.addChild( new MenuElement( "Coffee Shop"), new SampleMenuAction() );
   menu2.addChild( new MenuElement( "Diner"), new SampleMenuAction() );
   
   MenuElement menu1 = new MenuElement( "Shops" );
   menu1.addChild( new MenuElement( "Automotives"), new SampleMenuAction() );
   menu1.addChild( new MenuElement( "Books"), new SampleMenuAction() );
   menu1.addChild( new MenuElement( "Fashions"), new SampleMenuAction() );
   
   // Create the Main Menu,
   // and link the menu item to the menu containers created above.
   MenuElement main = new MenuElement( "Main Menu" );
   main.addChild( new MenuElement( "Shops"), menu1 );
   main.addChild( new MenuElement( "Restaurants"), menu2 );
   main.addChild( new MenuElement( "Attractions"), menu3 );
   
   // Show the Main Menu, this will make the Main Menu as the current screen
   menulist.showMenu( main );

Listing 2. onDisplay() implementation

public class SampleMenuAction extends TextBox implements MDisplayable
{
   
   public void onDisplay( MenuElement e )
   {
      this.setString( "You have selected menu item "+e.text );
      
      // Sample implementation that takes different action
      // based on different menu item being selected   
      if ( e.text.equals("Museum") )
      {
         //
         // Code to retrieve Museum directory
         // and display it in this text box
         //
      } else if ( e.text.equals("Art Galleries") )
      {
         //
         // Code to retrieve Art Galleries directory
         // and display it in this text box         
         //
      } else if ( e.text.equals("Exhibitions") )
      {
         //
         // Code to retrieve Exhibitions directory
         // and display it in this text box         
         //
      }
      
   }
}

Different MenuElements are associated with different MDisplayable implementations so that specific actions perform accordingly. MenuList is responsible for the visual rendering of all menu screens. Using MenuElement and various MDisplayable implementations, we can build a scalable menu system while keeping the structure clean and easily maintainable.

Wizard Dialog pattern

Many desktop applications use wizards in installation tools or configuration tools. In a wizard application, users are prompted through a series of screens. Each screen asks one or two questions. Two actions are allowed in wizard applications: Next and Back actions. Users press the Next button to proceed to the next screen. Users press the Back button to return to the previous screen and alter a previous answer. On mobile devices, wizard-style interaction involves a wireless application asking a series of questions to gather user input before performing an action. This is essentially a replacement for a Web input form, which doesn't fit well on mobile devices.

Let's look at an example—a local restaurant's search tool. This search tool uses city names and keywords as search criteria. The wizard application is implemented in two different Form classes. One Form contains a ChoiceGroup with a list of predefined city names. Another Form contains a TextField for users to input keywords. Each Form must have a Back command and Next command for navigation between pages. To make this example more interesting, users must enter as least three characters in the keyword input field.

Figure 3. A sample wizard application

A wizard application consists of several dialogs, all of which are linked sequentially by Back and Next commands. An important requirement is to allow developers to decouple these Forms from each other and control the screen flow separately. Developers should focus only on building the dialogs' content, not on the repeated components that control the flow. Another pattern, the Mediator pattern, provides a clean and elegant way to achieve this. A mediator is a middleman component that controls several related components. Figure 4 shows the Wizard Dialog pattern's UML diagram. The mediator is the WizardEngine class, and each individual dialog is a WDialog subclass. By subclassing the WDialog class, developers can focus their efforts on building the wizard's content. WizardEngine handles the screen flow automatically.

Figure 4. Wizard Dialog UML diagram

The WDialog class is an abstract subclass for the MIDP Form class. It allows your application to manipulate the WDialog as an ordinary Form object. When subclassing the WDialog class, you must implement an abstract method, initDialog(). The method's implementation builds the Form's screen content for gathering user input. The following is an initDialog() example that builds a form to prompt for city names selection.

Listing 3. initDialog() implementation that prompts for city names

public class WPage2 extends WDialog
{
   ChoiceGroup question1;
   
   public void initDialog()
   {
      setTitle("Step 2");
      
      question1 = new ChoiceGroup("Select a city name to search", ChoiceGroup.EXCLUSIVE, new String[]{"Toronto", "Ottawa", "Waterloo"}, null );
      
      append( question1 );
   }
}

Oftentimes, an application needs to validate user input before proceeding to the wizard's next screen. In our example, we require users to enter at least three characters for the keyword field. WDialog provides optional onEnter() and onLeave() methods for implementing data validation. The onLeave() method invokes every time a user moves to the next screen. An onLeave() implementation checks the data inputted by a user on the current screen. If the data is not valid according to its business rules, onLeave() returns WDialog.REJECT; otherwise it returns WDialog.OK. The framework will ensure the user cannot flip to the next screen if WDialog.REJECT is returned.

Similarly, the onEnter() method invokes when a WDialog screen is about to appear on the device. If this screen is ready to be shown, WDialog.OK is returned; otherwise, WDialog.REJECT is returned, and the framework will take the user back to the previous screen. The mechanism provides opportunities for a WDialog implementation to validate the prerequisites and post-requisites of entering and leaving a screen. The following is an example of onLeave() that checks the keyword field. An alert screen displays if the user enters less than three characters.

1 2 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more