The Source for Java Technology Collaboration
User: Password:



   

An Introduction to BlackBerry J2ME Applications An Introduction to BlackBerry J2ME Applications

by Edward Lineberry
01/24/2006

Contents
Building a User Interface
Listening for Events
Other UI Considerations
Establishing a Network Connection
Displaying the Results
Conclusion
Resources

Research in Motion's BlackBerry devices and architecture are commonplace in enterprise infrastructures, but beyond standard functions like email and calendaring, the platform goes largely underutilized. For the average Java developer--even one with no experience in J2ME--writing applications for the BlackBerry is fairly easy. In this article, I will give an overview of building a simple user interface, and, because networking is the very heart and strength of the BlackBerry platform, how to transmit data through the BlackBerry Enterprise Server to a CGI servlet.

The example application used in this article is a simple problem-reporting application that a service technician could use to create trouble tickets for computer problems. Issues reported from the mobile device would be stored on the server and centrally accessible. My goal is to show that developing useful BlackBerry applications for custom business processes can be simple and easy. Though they provide the basic building blocks of a full-featured application, the examples used in this article are just a starting point.

Getting started with BlackBerry development means getting used to the BlackBerry Java Development Environment provided by Research in Motion. Though it lacks many of the features of the better IDEs available to Java developers, the packaging and debugging conveniences that it does offer make it all but required. The good news is that the BlackBerry JDE can be freely downloaded from the blackberry.com website and it contains everything you will need to create J2ME applications for the BlackBerry, including a device emulator. The BlackBerry JDE is Windows-only, and though it may be possible to develop applications on other platforms, the emulator and debugger will not be available. I won't go into using the JDE in depth, but a full workspace file is provided in the Resources section of this article, so building and running the sample application should be easy.

Building a User Interface

In our application, we will create three Java classes: DataCapture, DataCaptureScreen, and ConnectionThread. The DataCapture class is the main class of the application and does little other than instantiate the UI class and the networking class.


screen = new DataCaptureScreen(); 
pushScreen( screen );

Our application extends UIApplication--the base class for all BlackBerry applications that have a user interface--and the pushScreen() method makes our UI active. In the case of our example application, there is only one screen. However, the UIApplication class contains a stack of screens. To display a new screen, simply invoke pushScreen() to push it onto the stack. When popScreen() is called, the new screen closes and the next one on the stack is displayed.

Everything the user sees and interacts with is contained in our DataCaptureScreen class. The constructor handles instantiation of all of the UI elements. Once these have been created, they work as expected, with no additional programming required. Developers familiar with Swing or AWT programming will be in comfortable territory. It is possible to create MIDP applications that run on devices other than the BlackBerry, but the BlackBerry API provides a host of classes that allows developers to take full advantage of the platform. For applications that will be deployed only on the BlackBerry, the device-specific APIs should be used. This is especially true for UI elements, as users will expect the application to behave in a ways similar to the standard applications deployed to the device.

For most types of user input, there is a corresponding field or field filter. The DateField class presents the user with an input that can be changed using the space bar and scroll wheel to select the desired state and time.

 
DateField dateTimeField = 
    new DateField("Date: ", System..currentTimeMillis(), 
    DateField.DATE_TIME);

In this constructor, the field is instantiated with the current date and time through the second argument. This first argument is the label for the field, which displays on the same line. The third argument to the constructor is the style for this field. Passing DateField.DATE or DateField.TIME will create a field for date-only or time-only entry, respectively.

The other fields on the screen provide similar arguments, such as the field label passed in first, and are created in much the same way as the DateField.


private ObjectChoiceField category = 
    new ObjectChoiceField("Category:", 
    new String[] 
    { "Hardware", "Software", "Network" });

private AutoTextEditField user =
    new AutoTextEditField("User:", "");

private BasicEditField phone = 
    new BasicEditField("Contact #: ", "", 10,
    EditField.FILTER_PHONE);

private AutoTextEditField notes =
    new AutoTextEditField("Notes:", "");

The ObjectChoiceField provides an interface similar to a drop-down menu within a web browser. Users can cycle through the list by clicking the space bar, which allows for fast and reliable data entry. The AutoTextEditField is for standard text entry. It differs from the BasicEditField in that any data entry shortcuts defined on the device are respected when the user types within this field. Also, the initial letter is capitalized.

The field defined for entry of a phone number begins as a BasicEditField, but two restrictions are placed on it through the third and fourth arguments.

 
private BasicEditField phone =
    new BasicEditField( "Contact #: ","", 10, 
    EditField.FILTER_PHONE);
 

The third argument is the field length. The fourth argument is the field "style," a set of constants that restrict the data that can be entered into the field. Creating a field using the EditField.FILTER_PHONE argument restricts the characters for that field to numerals, dashes, parentheses, and the "x" character. This is especially handy on the BlackBerry, as most devices use the same keys for numbers as for letters. Using entering data into a field that only accepts numbers, these keys are automatically translated to input numbers without forcing the user to press the Shift key. A variety of other filters and styles are available, and it is recommended that the developer take advantage of them when appropriate. Field styles make user input faster and more reliable, and can make data validation easier for the developer.

Figure 1 shows these fields as rendered by the emulator.

Application Screen Shot
Figure 1. Input fields

Listening for Events

The last element in our user interface is the button for sending the data.


private ButtonField sendButton = new ButtonField("Send");

Now that the DataCaptureScreen has the appropriate elements as instance properties, all that is left is to put them on the screen; a task handled by the constructor.


setTitle("Data Capture");
add(dateTimeField);
add(category);
add(user); 
add(phone); 
add(notes); 
add(new SeparatorField()); 
FieldListener sendListener = new FieldListener();
sendButton.setChangeListener(sendListener);
add(sendButton);

As the DataCaptureScreen class extends the MainScreen class, it inherits the methods necessary for placing components on the screen. More complex and sophisticated layout managers are available, but the simple vertical layout manager of the MainScreen class is enough for most uses. Each field is placed on a new line, beneath the one before it. Labels are left-justified; fields are right-justified.

The final piece of our example user interface is the ButtonField and the associated FieldChangeListener, which is implemented as an inner class.


class FieldListener implements 
    FieldChangeListener {
        public void fieldChanged(Field field,
            int context) {
                //button action
    }
}

Invoking setChangeListener() on the ButtonField activates the button in the user interface. It's possible to have multiple buttons using the same FieldChangeListener interface. In the case of our example, we have only one, but simply testing for equality between the Field argument in the fieldChanged() method and the instance of the field or button will determine which registered field has changed.

Other UI Considerations

The default close behavior for classes that extend MainScreen is to present a save dialog box. Because our application has no concept of persistence, we suppress the dialog by overriding onClose(), something you'll want to do most of the time.

Also, because the example application has only a single action, one button works well. In many instances, you will want to make use of the context menu, which is available to users on the device by depressing the scroll wheel. This menu makes actions accessible from anywhere on the screen, just as right-clicking with the mouse does in a desktop environment. Given the small screen, buttons can quickly clutter the user interface. The menu is more desirable for screens with multiple actions or navigation options.

Establishing a Network Connection

Now that the user has entered the information into the user interface and pressed the Send button, our ConnectionThread class will handle transmitting the data across the network. In an environment using the BlackBerry Enterprise Server, this connection can take place "behind the firewall." The wireless transmission from the device is encrypted, and the BES can connect to intranet servers not exposed to traffic from the public internet. In a real-world application, the https protocol might be a better choice, not only because it provides additional security, but also because it provides authentication, allowing the receiving server to know who sent the data.

Custom BlackBerry applications that attempt network connections display a prompt to the user before opening the connection. However, only one thread may have access to the user interface at a time on a BlackBerry device. If a connection is made from the MainScreen thread, the screen will be locked and the user will not see the prompt. The networking thread in the example application runs in an infinite loop, checking each time for a change in the Boolean start or stop class properties. The interface to this class comes in the post() method.


public void post(String url, String data) {
    this.url = url;
    this.data = data;
    sendResult = false;
    sending = true;
    start = true;
}

The class properties in the ConnectionThread instance are set with the arguments. With our URL and data in place, the run() method detects that start is now true and makes the network connection.


private void httpPost() {
    HttpConnection conn = null;
    OutputStream out = null;
    int responseCode;

    try {
        conn = (HttpConnection) Connector
            .open(url);
        conn
            .setRequestMethod(
            HttpConnection.POST);
        out = conn.openOutputStream();
        out.write(data.getBytes());
        responseCode = conn.getResponseCode();

        if (responseCode != 
            HttpConnection.HTTP_OK) {
            sendResult = false;
        } else {
            sendResult = true;
        }

        start = false;
        sending = false;

        } catch (IOException e) {
            start = false;
            sendResult = false;
            sending = false;
    }
}

We use the Connector class to get our HttpConnection. This is a factory class that handles the device-specific networking issues and returns an HttpConnection without the developer having to worry about the details. The Connector class has powerful features for controlling the network connection, but the defaults will work in most cases. If the device is outside of network coverage, or otherwise unable to connect to the server, the user must try again later. In a real-world application, the data could be persisted and sent at a later time. Posting the data to the URL works the same as in J2SE, but getting the results is a little more difficult on the BlackBerry because of the threading issues.

Displaying the Results

The MainScreen class watches the ConnectionThread until it is through sending, then reads the result and displays a pop-up message. A "Sending..."message is displayed to the user, as seen in Figure 2, so that the device does not appear to be frozen.

Sending Dialog
Figure 2. "Sending" dialog


while (connThread.sending) {
    try {
       Status.show( sb.append(".").toString() );
        Thread.sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

if (connThread.sendResult) {
     Status.show("Transmission Successful");
} else {
     Status.show("Transmission Failed");
}

Each thread has its own responsibility. In this case, the application waits for the connection to succeed or fail, but it's possible to allow the user to continue to work while the networking thread attempts to connect.

Conclusion

The power and usefulness of mobile devices lies in the ability to extend existing applications beyond the desktop or browser. With the BlackBerry, this power comes standard with regard to email and calendar. However, developers can bring many more useful tasks to network-connected mobile devices. Though J2ME and the BlackBerry API may be unfamiliar to some, I hope that this article shows that building custom applications for BlackBerry devices does not have to be difficult.

Resources

Edward Lineberry is a Senior Consultant for Simplified Technology Solutions in Atlanta, Georgia.

View all java.net Articles.

 Feed java.net RSS Feeds