Showing posts with label blackberry. Show all posts
Showing posts with label blackberry. Show all posts

Blackberry Design Guidelines - Tips on Designing the User Interface


I commonly hear from designers that engineers don't have the right-brain skills for interface design. They say that the essence of good design is functional simplicity and since engineers think end users are only interested in cool features (because that's what the engineers themselves are interested in) the result of an engineer designing an interface will be a bloated, feature-laden mess. One of the most common examples they will bring up is the dreaded Sony remote control, take a look at the sample picture of a remote from one of Sony's A/V receivers.

When you look at the remote on the left can you blame the designers for the stereotype? Yes, I'm pretty sure this remote was designed by engineers, here's why:

  1. There are 65 buttons total on a remote that measures no more than 3"x10"

  2. 20 tiny buttons in a grid at the top of the remote, each with multiple functions spelled out in tiny type. How can the user distinguish the functions easily?


  3. Most of the buttons are the same dimension making it difficult to find the correct one in a dimly lit room


  4. The four buttons at the bottom appear to perform four functions each for a total of 16 functions. Feature overload!

If you're wondering what the smaller control on the right is for, get this: it's a remote that also comes with the Sony A/V receiver that's meant to simplify the primary remote. It's almost like Sony realized too late that the primary remote was terrible and the best solution was to throw in another remote. Don't get me wrong: I love Sony products but I've always felt that the software and hardware interface of their devices is their biggest flaw.

Software Engineers can do Better


I know the idea is somewhat cliched by now but pick any one of Apple's products, iPhone, iPod, OS X, etc., examine the user interface and you'll see what I mean: complex functionality disguised behind a simple and easy to use interface. I mean I know it's not software but even their Magic Mouse is a wonder of human interface principles.

By all accounts the iPod saved Apple but how did that happen considering Creative and other companies dominated the marketplace for MP3 players when the iPod was released? Originally the iPod only worked on Macs but when Apple released iTunes software for Windows, sales skyrocketed and the rest is history. Creative's players were rated higher, had greater capacity, and longer battery life but iPods eventually outsold them by a large factor.

If we ignore Steve Job's "reality distortion field", I'd wager that one major reason was the user interface of the iPod (including the mechanics of the wheel) combined with simplified software for the desktop (iTunes). Creative and other companies designed their interfaces with so many features they forgot to focus on the most important one: how does the end user navigate 1000's of songs quickly and efficiently. Apple's engineers understood that the screen is tiny and overloading it with too much extraneous "stuff" will overwhelm the user. Users are on the go when they break out their player therefore menus shouldn't be too complex or deep for quick access.

If you can't stand the Apple example (I know Apple can be polarizing) then take a look at the Flip series of handheld video cameras. This startup company had the idea of making an inexpensive and tiny camcorder that was plain easy to use for people wanting to upload to YouTube and they succeeded - recently Cisco bought the company for $590 million dollars and Sony, Canon, and other manufacturers are rushing to catch up. Why is the Flip so popular? Again, I think it's mainly due to the simple interface on the camera and the easy desktop software that came with it. Take a look at the Flip hardware interface versus a typical Canon from a couple years ago:



I think you're getting the idea that I feel simple user interfaces can be really important to successful software and it applies to Blackberry app design as well. As final affirmation, take a look at how focusing on design has served Apple's stock price over the last 10 years:




Develop like an Engineer, Think Like a User


Short of spending time taking a class on Human-Computer Interaction Principles or reading long (boring?) textbooks (some of my favorites are linked at the bottom of this article), there are a few simple suggestions I have for you to keep in the back of your mind while you're programming the interface to your Blackberry app. I'll use images from Blackberry programs found on the App store to illustrate my points because I think it helps to have examples. I've gone to lengths to disguise the name of the apps in the hopes of not offending anyone who developed them - apologies in advance if you recognize your app on here.

As preface to the discussion, in my opinion, it's easier to design an interface with lots of features - after all, you don't have to think as much, just throw everything in. Simple interfaces require a great deal of contemplation before coding since you're making tough decisions about what to get rid of and that isn't always easy. Think of simple interface design as forging a sword - it requires a lot of labor to grind out all the imperfections, to fold the steel repeatedly, and most importantly, making it razor-sharp. In the end, when the swordsman has to pull out his weapon, he needs to have the confidence that it will serve it's sole purpose to perfection (yeah, kill people) and that it's not going to get in his way (no unnecessary features).

Without further ado, my list of user interface design recommendations:

#1 - Don't put too many options in menus


Blackberry menus can be customized on a per-screen basis thus it doesn't make sense to have the main menu options as part of each screen. Make contextual menus do a limited number of things otherwise the menu will be overwhelming. Here's example of menus done wrong on the Blackberry:



The designer chose to put every option under the sun in the menu including choices that extend "below the fold" e.g., where the user has to scroll to see them. Additionally, they chose to include five different search types and the menu takes up the entire screen because the verbiage is too long. One suggestion for improvement of this menu is to have one option for "Search" that opens a search screen with the different options laid out as checkboxes or some other method.

#2 - Pay Careful Attention to Fonts and Readability


There's an impulse to differentiate your app from others by using uncommon fonts in your app (think Comic Sans). Don't do it! (unless you're working on a game and it fits the theme) Remember, you want your user to be able to easily read the content of your app and most of the time a common font is the best choice. Another consideration is to ensure that fonts within graphics are readable. For example:



The main font for the content of the contact is fine but it's bold and is definitely larger than the menu options at the top. It's distracting and the app would be served well to reduce the font size. Additionally, take a look at the Contacts button that's pressed at the top left. The gradient used there is cutting off the top of the words making it hard to read. I'd suggest changing the font color to a darker shade when the button is active.

#3 - Space is Your Friend


Sometimes you have to just let the content of your app "breathe". In other words, since the screen real estate is so tiny on most Blackberry devices you might have the tendency to try and fill up the space with a ton of data - don't. Sometimes a graphic, although more difficult to add/program, can do the trick. Remember your user is going to be quickly glancing at the screen while on the go and, as they say, a picture is worth 1000 words. For example, compare these two stock quote apps:



Yes, they both give similar information yet in the first example the user can glance at the image of the current stock price and immediately know the day's trend and if they should be worried. Also, going back to my point on fonts, in the first app the font size chosen for the latest quote is larger than the rest of the fonts giving it higher priority. Your eyes are drawn to the image and that quote while you'd have to search the list on the second one to distinguish where the quote resides. Which one would you choose if you were just comparing screenshots?

Also, notice how there's space around each of the elements in the first app. It gives a certain "lightness" to the app - what people these days call a "clean look". The second app has a lot of whitespace (I'd consider wasted real estate) but it just doesn't have a finished look.

#4 - Keep it Clear Part 1- Make Navigation Obvious


Users don't have the patience to spend more than few minutes figuring out how to work your app. They want to quickly navigate your app to find the features they want and you'll want to make it easy for them. Large icons, simple menus with few options, minimal background noise are all important to the success of your app. If you're finding that you have too many navigation options consider paring back the scope of your app - e.g., removing unnecessary features. Take a look at these:




While I certainly appreciate the fact that this app has to have a bunch of features (it's the front end for a complex web application) I'm just not sure if the choice to place 15 tiny icons at the top of the screen is a wise one. Even after using the app for a long time, the end user will likely always have problems figuring out what icon stands for which function. Yes, it is nifty that when you scroll across it the name of the function appears next to the icon but think of all the time the user will waste scrolling back and forth until they find the function they were looking for. I'd wager that 5-10 of those options could be placed in a menu or some other method used to place only the most commonly used features on the main nav.


#5 - Keep it Clear Part 2 - Eliminate Extraneous Info


Yes, keeping it clear is important. You never want to have extraneous information on screen for the user because they might be looking at your app while driving, in a meeting where they can only quickly check it, etc. For this reason you want to keep it as simple and clear as possible and to do so you'll want to ensure all the features of your app are entirely necessary. Ensure you prevent something that Apple calls "Feature Cascade" - "If you are developing a simple application, it can be very tempting to add features that aren’t wholly relevant to the original intent of the program. This feature cascade can lead to a bloated interface that is slow and difficult to use because of its complexity. Try to stick to the original intent of your program and include only features that are relevant to the main workflow." (Human Interface Guidelines)

While the images below aren't examples of feature cascade, they demonstrate that eliminating extraneous information can improve an app:



I modified the image on the right to cut out the unnecessary, self-congratulatory, images at the bottom. Before, the focus on the screen was on the colorful icons but after the modification you're not distracted. Don't you think it looks and feels much better?

#6 - Don't Forget Usability Testing


When you're spending all your time focused on developing your app you quickly lose your objectivity around its functionality. You know your app inside and out and you'll begin to assume the end user will as well. This is when usability testing comes into play. It's quite simple - just load your app on a phone and pass it around to your friends, your family, anyone who hasn't seen it before and ask them to perform certain tasks. Watch them carefully to see what they are doing when they try and tackle the tasks you throw at them - watch the phone but also observe the user's face to see if there is any frustration or quizzical looks. Ask them why they're having trouble if they look frustrated and take notes.

When you've gotten 4-5 people to test the app, take careful consideration of the feedback they've given. You can safely ignore most comments about color since it's a subjective topic. Instead, focus on areas where navigation was a problem or where finding a certain function took too long. Use the principle of Occam's Razor to simplify the app if these kind of problems arise. In other words, don't add features thinking it will simplify things - try removing them instead. Trust me, it will be a whole lot easier!


To be Continued...


Design is an enormous topic so I'll continue discussing this in future posts. The main takeaway here is that end users have a limited amount of patience and goodwill towards your application. If they can't figure it out in the first five minutes or it's not pleasing to the eye then they won't be recommending it to their friends and you'll probably get bad reviews in the app store. As a secondary takeaway, here are the key bullet points from the Blackberry UI Guidelines:


  • Use or extend existing UI components where possible so that your application can inherit the default behavior of the component.

  • Follow the standard navigation model as closely as possible so that a particular user action produces a consistent result across applications. For example, allow users to open the context menu in all applications by clicking the trackball or trackpad.

  • Support and extend user tasks in useful ways. For example, when users download an application, the application should open automatically. The application should also be saved in the Applications folder.



When you design your application, also consider the following guidelines:


  • Stay focused on users' immediate task. Display only the information that users need at any one moment.

  • Verify that the actions that are available in the menu are relevant to users' current context.

  • Minimize the number of times that users need to click the trackwheel, trackball, trackpad, or touch screen to complete a task.

  • Design your UI to allow users to change their mind and undo commands. Users sometimes click the wrong menu item or button accidentally. For example, use an alert dialog box to notify users of a critical action such as deleting data from their BlackBerry devices.

  • Display information in a way that makes effective use of the small screen.



Suggested Reading and Links



Using threads for basic tasks on the Blackberry is not necessarily as difficult as it may first appear. You can leverage RIM's net.rim.device.api.system.Application class to synchronize with the EventLock and perform whatever tasks your threading model requires. Of course when programming games or intricate UI component interaction using threads can be complex and downright challenging. Thankfully, for most apps you're likely to do simple threading tasks that don't require such interaction. In order to modify UI components you must perform all the work within the UI thread and there are two general rules that you'll have to follow:
1) Modify UI components using the invokeLater() method, 2)Never call an HTTP request within the UI thread.

The invokeLater() method is used when changes are made to the UI outside of the main UI thread. It places your runnable object into your application's main event queue and is processed after all events pending in the main queue are complete. In other words, it's similar to regular Java threads where you use the join() method so your code waits for other threads to complete before grabbing the eventlock. Making HTTP requests within the UI thread will most assuredly make your application slow down and could make it crash. Instead of using invokeLater() or other methods to grab the UI thread you'll want to do something like the following:

new Thread(){
public void run(){
HttpConnection http_con = (HttpConnection)Connector.open("http://berrytutorials.blogspot.com");
}
}.start();



Here we're creating a new thread that opens the HTTP connection but it will run as a background process and not tie up system resources on the main UI thread. For more details on opening HTTP check out the HTTPDemo included in the RIM samples that are part of your component pack download for Eclipse.

Background


For the example we'll be using the code from a previous tutorial on Listfields and will modify it to make updates to the list from a thread. Take a few minutes to read through that code, copy it and place it into a new Blackberry project in Eclipse - otherwise you can get the sample code in it's entirety here.

Thread.sleep() will be used to simulate your code performing data processing or making an HTTP connection that will occur in the background of the app. Once that's complete the listfield will be updated with a simple string that will include the thread name and an element number that is incremented for each update so you can see the thread working. It wouldn't take much modification to modify the code below and, for example, make a connection to Twitter via their API to grab updates to the people you follow, then update the list with that content.

You might ask, "How does the ListField know when to update itself?" - what I'm doing in the code is leveraging the Observer design pattern to attach the ListField as a "observer" to the Thread we create. It will "listen" to the Thread until it's notified of an update and then will add the new message to the list and redraw itself. Here's an image that will serve to give you an overview of what the Observer pattern is doing, courtesy of javaworld.com:




For the sample code, the Subject shown in the image above will be the Thread we create and the Observer is the ListField itself - once the Thread has slept (simulating the HTTP connection or data processing task) it will notify the Listfield of the change. To do this appropriately we'll create an interface for the ListField to implement containing the update() method and will create the addObserver(), removeObserver() and notifyObservers() methods in the Thread class. The reason we use the interface here is that many different Classes might need to observe the Thread's progress and could be attached as Observers. The Thread loops through the attached Observers and informs them of the changes via the the update() method. The end result will be a ListField that auto updates elements every 10 seconds as in the screenshot below:



In this sample we don't necessarily have to use the interface since we're only attaching one Observer but it's good practice to see how it works. If you're not familiar with the Observer pattern take a few minutes and read through the following links: Background on Design Patterns GangofFour - Observer Pattern, PDF on Observer Pattern

Subject Code - Create the Thread


First we need to add a private class that is used to implement the Thread itself. Following the Observer pattern we'll add the methods 'addObserver(MyListField mlf)' and 'removeObserver(MyListField mlf)' that permit the thread to add/remove Observers to itself and a 'notifyObservers()' function that will inform observers that are attached to the Thread that a change has occurred. Here's the code:


//Runnable class
private class CheckForUpdates implements Runnable{

private String updatedMessage;
private Vector observers;

public CheckForUpdates(){
observers = new Vector();
}

//Attach the observer to the class
public void addObserver(MyListField mlf){
observers.addElement(mlf);
}

//Not used for this example - remove an observer
public void removeObserver(MyListField mlf){
observers.removeElement(mlf);
}

//Go through vector of observers and call update on them
//Sending the updatedMessage String.
public void notifyObservers(){
for(int i=0;i ((MyListField)observers.elementAt(i)).update(updatedMessage);
}
}

//Overridden runnable method. Simulates checking external resource(such as HTTP call to remote server)
//using the sleep() method then changes the message and notifies the attached observers.
public void run(){
int counter = 0;
try{
while(true){
//Simulate an HTTP connection OR data processing
Thread.sleep(10000);
counter++;
updatedMessage = Thread.currentThread().getName() + "- Element " + Integer.toString(counter);
notifyObservers();
}
}

//Simply return if interrupted.
catch (InterruptedException e){
return;
}
}


}



Note that we're creating a private Vector to hold the observers that are attached to the instance of the thread although there will be only one observer for the example. Additionally, if you take a look at the run() method, you'll see that we loop indefinitely, calling Thread.sleep(10000) and when the Thread wakes it increments the counter, updates the message to pass to the observers, and calls the 'notifyObservers()' method. If this were production you'd want to add some code that can stop the Thread based on a keystroke, menu option, or some other method, otherwise it will eventually consume all the resources available.

Observer Code - Create the Interface and Update Method


The next step is to create the Observer interface and the update() method, in this case contained in the MyListField class. Here's the code:


public interface ObserverInterface{

public void update(String message);
}

....
private class MyListField extends ListField implements ObserverInterface{
.....
.....
.....
//Update function takes in a message to add to the list,
//inserts it into the list, and calls invalidate to repaint the list
public void update(final String message){
final int i = this.getSize();
final ListCallback mlc = (ListCallback)this.getCallback();
final MyListField mlf = this;
UiApplication.getUiApplication().invokeLater(new Runnable(){
public void run(){
mlf.insert(i);
mlc.insert(message,i);

}
});


}



The update() method grabs the UiApplication event lock by calling 'invokeLater()' with a new Runnable() where we insert the String into the List. Thus, the main UI thread will complete whatever functions it's performing and pass the lock to our thread which updates the List and redraws it to the screen.

Constructor code


Finally, add the following to the constructor of the ListFieldTest class:

//Declare the Runnable Thread
CheckForUpdates cfu = new CheckForUpdates();

//Attach the Observer - in this case myList is the observer
cfu.addObserver(myList);

//Declare a new thread with our Runnable as input and start thread
Thread t = new Thread(cfu);
t.start();



That's all there is to it. We create an instance of our Thread, attach the List as an Observer so the thread can call the List's update() function when there's a change, and simply start the thread. Side Note: Java has Observer/Observable as part of the language specification however RIM does not and as a result you can't leverage the code that's already out there. Nonetheless, implementing the pattern wasn't too difficult, at least for this simple example, and understanding how design patterns work will really make life easier.

User Defined Buttons - Create a Custom Button From an Image

While it's tempting to use the standard built-in ButtonField class to create user-selectable buttons for your application so you can rapidly release it to the public, I'd recommend delving into creating your own. Going through the process will give you a good understanding of how listeners work and how to detect and react to user input within the Blackberry environment. I'll provide a simple example of just how to do that with a comparison between using our custom button versus the ButtonField class. The end result of our efforts will be a screen with a custom search button and a standard ButtonField button, as shown below:






Note that all the code in each sections below is intended to be combined into one file within the project space.

Create the Custom Button png Using Inkscape


As I've stated in other posts, I recommend using Inkscape for creating the custom vector graphics you'll use on your applications as it's free and is really a great substitute for Illustrator. For this example I crafted two custom search buttons in just a few minutes using the standard "magnifying glass" as inspiration to distinguish it's use for search. One of the images has grey highlights and the other has a glow effect which our app will switch to when the user rolls over it.

Make sure that you keep the end user in mind when you're designing the buttons since you want to make sure they are immediately recognizable for the respective action they are supposed to perform - you don't want to confuse the user because they'll turn off your app before spending 10 minutes trying to figure out how it's supposed to work. I'm not going to post the images I created as separate files to download - instead take some time to learn Inkscape and come up with a few on your own. The time you invest will pay off later (if you insist on being lazy you could cut it out of the image above and convert to .png).

Create the Main Class and First Part of Constructor


Again, this is a simplified example and as a result we are doing most of the work within the constructor of the custom Button class. We are creating MyCustomButton as a private class of the overall MyButton class and if you want to jump ahead to see that code it's at the bottom of the post. In this first part the constructor creates a HorizontalFieldManager that will have a gradient background painted on and will act as the container to layout the buttons. Note that I've tried to document the code with lots of descriptive comments to help understand what's going on.


import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;

public class MyButton extends UiApplication {

public static void main(String[] args){

//main entry point
MyButton theApp = new MyButton();
theApp.enterEventDispatcher();

}


public MyButton(){
//Declare the Custom button and send it the path to the icon images
MyCustomButton mcb = new MyCustomButton("search_button_on.png", "search_button_off.png");

//Declare the normal ButtonField with name
ButtonField bf = new ButtonField("Search");

//Get the device width and height
final int width = Display.getWidth();
final int height = Display.getHeight();

//Create the mainScreen - this holds the _hfm manager
MainScreen mainScreen;
mainScreen = new MainScreen();


HorizontalFieldManager _hfm;

//Draw background gradient on this manager
_hfm = new HorizontalFieldManager() {

public void paint(Graphics g)
{


//Variables for drawing the gradient
int[] X_PTS_MAIN = { 0, width, width, 0};
int[] Y_PTS_MAIN = { 0, 0, height, height };
int[] drawColors_MAIN = { Color.BLACK, Color.BLACK, Color.DARKBLUE, Color.DARKBLUE};


try {
//Draw the gradients
g.drawShadedFilledPath(X_PTS_MAIN, Y_PTS_MAIN, null, drawColors_MAIN, null);

} catch (IllegalArgumentException iae) {
System.out.println("Bad arguments.");
}

//Call super to paint the graphics on the inherited window
super.paint(g);


}

//Sublayout is passed the width and height of the parent window and will tell the window manager
//how to layout the buttons, images, etc.
protected void sublayout(int w, int h) {

//GetFieldCount returns the number of fields attached to the instance of this manager.
//and lays out the position
if (getFieldCount() >0) {

//Get the custom button we've created and add it at coordinate (100,160)
Field customButton = getField(0);
layoutChild(customButton, w, h);
setPositionChild(customButton,100,160);

//Get the standard Blackberry Button we've created and add to coordinate(220,160)
Field standardButton = getField(1);
layoutChild(standardButton, w, h);
setPositionChild(standardButton,220,160);


}



setExtent(width,height);

}


};
...





Declare the Buttons and FieldChangeListeners


Finish off the constructor portion by declaring two custom FieldChangeListeners, setting the Listeners to the Buttons, adding the buttons to the HorizontalFieldManager, and adding the HFM to the main Screen. The FieldChangeListener will perform the action defined in the fieldChanged() method. when the user clicks the button.

Here we are triggering a Dialog alert so when the user clicks either of the buttons they'll get this:



In real code you'll do something more realistic such as push a new screen to the stack that performs whatever functionality you intend for the buttons.


FieldChangeListener customListener = new FieldChangeListener() {
public void fieldChanged(Field field, int context) {

Dialog.alert("Success!!! You clicked the Custom Button!!!");


}
};

FieldChangeListener standardListener = new FieldChangeListener() {
public void fieldChanged(Field field, int context) {

Dialog.alert("Success!!! You clicked the Standard Button!!!");


}
};
mcb.setChangeListener(customListener);
bf.setChangeListener(standardListener);

//Add our custom button to the HorizontalFieldManager
_hfm.add(mcb);
_hfm.add(bf);
//Push the HorizontalFieldManager to the stack
mainScreen.add(_hfm);
pushScreen(mainScreen);


}//End Ctor




Create the Custom Button Class


The meat of the code lies within the MyCustomButton class that extends the abstract Field class and implements the DrawStyle interface. We're taking two strings in the constructor that are the paths to the image files and using the Bitmap class method "getBitmapResource()" to import the images and set them to our private onPicture and offPicture variables.

The getPreferredHeight() and getPreferredWidth() methods return 80 since the images I've created for the custom button are 80x80px but you'll want to set these to the size of your button image. The most critical methods of the code and what they do are as follows:

  • onFocus() and onUnfocus(): these functions set the _currentPicture variable to the correct image when the user rolls over the button using the paint() method. The image is redrawn after the change by calling the invalidate() method

  • paint(): draws whatever image the _currentPicture variable is set to onthe screen.

  • fieldChangeNotify() and navigationCLick(): alerts this registered button's listener we've attached that the user has clicked the button. The listener code is subsequently triggered - the Dialog alert is shown to the user.


Refer to the attached custom Button code:

//Custom private class that creates the button and switches the image depending
//on the return value of onFocus()
private class MyCustomButton extends Field implements DrawStyle{

private Bitmap _currentPicture;
private Bitmap _onPicture; //image for "in focus"
private Bitmap _offPicture; //image for "not in focus"
private int width;
private int height;

//Ctor: pass path to on/off images you're using.
MyCustomButton (String onImage, String offImage){
super();
_offPicture = Bitmap.getBitmapResource(offImage);
_onPicture = Bitmap.getBitmapResource(onImage);
_currentPicture = _offPicture;

}

public int getPreferredHeight(){
return 80;
}

public int getPreferredWidth(){
return 80;
}


public boolean isFocusable(){
return true;
}

//Override function to switch picture
protected void onFocus(int direction){
_currentPicture = _onPicture;
invalidate();
}
//Override function to switch picture
protected void onUnfocus(){
_currentPicture = _offPicture;
invalidate();
}

protected void layout(int width, int height) {
setExtent(Math.min( width, getPreferredWidth()), Math.min( height, getPreferredHeight()));
}

//update the fieldchange
protected void fieldChangeNotify(int context) {
try {
this.getChangeListener().fieldChanged(this, context);
} catch (Exception exception) {
}
}

//Since button is rounded we need to fill corners with dark color to match
protected void paint(Graphics graphics) {
graphics.setColor(Color.BLACK);
graphics.fillRect(0, 0, getWidth(), getHeight());
graphics.drawBitmap(0, 0, getWidth(), getHeight(), _currentPicture, 0, 0);
}

//Listen for navigation Click
protected boolean navigationClick(int status, int time){
fieldChangeNotify(1);
return true;
}

}


}



I think you'll agree that the custom button looks much slicker than using the stock Blackberry buttons - if done right it will give your app a great degree of elegance.

Create a Custom Listfield - Change Highlight Color when Scrolling

When you're programming for Blackberry you will likely find yourself in need of displaying a list of items that are selectable to the end user. The ListField class in the Blackberry API is extremely versatile and should be your first choice when considering how to display a list of options.

Key to coding the ListField is to register a ListFieldCallback - a class that implements the ListFieldCallback interface and can be thought of as a data structure that holds the contents of the List and permits you to modify, update, delete, and read these contents. In other words, the ListField handles the painting of the list and the Callback handles the storage of the list contents.

For this article I'll show you how to get a ListField up and running on the Blackberry and how to customize the highlighting of each row when the user scrolls across the list. For demonstration purposes we'll create the ListField as a private class within the main class that extends UiApplication and simply add our field managers that will hold the ListField to the MainScreen. Note that the code samples do not include the required code for capturing the user selection and performing an action on it - I may write another tutorial around that if people request it however that's pretty straightforward. In the end, our main goal is to have a list that looks like the one below, where the user selection is highlighted in a different color as they scroll across the list:







Write the Constructor


Please note that all the code below is continuous and should be contained in one file. I'll put a link to download the entire code in one file if the demand is there. However, I think it's a good learning experience to see each piece, understand how it works and put it together at the end into a cohesive working program. First, we'll import the necessary classes and create the main function for our example. I'm going to do all the heavy lifting in the constructor of the class - please note that the VerticalFieldManager and the HorizontalFieldManager in the next sections are also part of the constructor. Also, we're declaring instances of the ListField and ListFieldCallback early in the constructor and will flesh out those classes a bit later. Here's the first part of the code:



import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;

import java.util.Vector;

public class ListFieldTest extends UiApplication {

public static void main(String[] args){

//main entry point
ListFieldTest theApp = new ListFieldTest();
theApp.enterEventDispatcher();

}


public ListFieldTest(){

HorizontalFieldManager _hfm;

//The _vfm will hold the ListField and we'll add it to the _hfm
VerticalFieldManager _vfm;

//Create the vars for ListField creation
ListField myList;
ListCallback myCallback;

//Get the device width and height
final int width = Display.getWidth();
final int height = Display.getHeight();

//Create the mainScreen - this holds the _hfm and _vfm managers
MainScreen mainScreen;
mainScreen = new MainScreen();

//Private class that we will create in a minute
myCallback = new ListCallback();
myCallback.erase();

myList = new MyListField();
myList.setCallback(myCallback);

//Populate the list with sample elements
for(int i=0;i<20;i++){
myList.insert(i);
myCallback.insert("Element #" + Integer.toString(i), i);

}



Create the HorizontalFieldManager


Now we need to create the HorizontalFieldManager that will hold the ListField and VerticalFieldManager. The HFM will act as the "parent" container and will hold the VFM child and we will also use it to draw the gradient. Refer to the code below for the HorizontalFieldManager:



//Draw background gradient on this manager and add VerticalFieldManager for scrolling.
_hfm = new HorizontalFieldManager() {

public void paint(Graphics g)
{


//Variables for drawing the gradient
int[] X_PTS_MAIN = { 0, width, width, 0};
int[] Y_PTS_MAIN = { 0, 0, height, height };
int[] drawColors_MAIN = { Color.BLACK, Color.BLACK, Color.DARKBLUE, Color.DARKBLUE};


try {
//Draw the gradients
g.drawShadedFilledPath(X_PTS_MAIN, Y_PTS_MAIN, null, drawColors_MAIN, null);

} catch (IllegalArgumentException iae) {
System.out.println("Bad arguments.");
}



//Call super to paint the graphics on the inherited window
super.paint(g);


}

//Sublayout is passed the width and height of the parent window and will tell the window manager
//how to layout the buttons, images, etc.
protected void sublayout(int w, int h) {

//GetFieldCount returns the number of fields attached to the instance of this manager.
//and lays out the position
if (getFieldCount() >0) {

Field searchRes = getField(0);
layoutChild(searchRes, width, height);
setPositionChild(searchRes,0,0);

}



setExtent(width,height);

}


};



Create the VerticalFieldManager



In the VerticalFieldManager declaration we will pass in the VERTICAL_SCROLL option so the lists scroll properly within the container once we add the ListField. Additionally, make sure to override the navigationMovement() function calling this.invalidate() otherwise when you scroll the ListField won't redraw as the user scrolls over the options. Try it without the invalidate() call to see what happens. Here's the final code for the VFM in the constructor:


_vfm = new VerticalFieldManager(Manager.VERTICAL_SCROLL|Manager.USE_ALL_HEIGHT|Manager.USE_ALL_WIDTH) {

public void paint(Graphics g)
{
g.setColor(Color.GRAY);
super.paint(g);

}

protected boolean navigationMovement(int dx, int dy, int status, int time){
this.invalidate();
return super.navigationMovement(dx,dy,status,time);
}


};
//Add the list to the verticalFieldManager
_vfm.add(myList);

//Add the verticalFieldManager to the HorizontalFieldManager
_hfm.add(_vfm);
//Finally, add the HorizontalFieldManager to the MainScreen and push it to the stack
mainScreen.add(_hfm);
pushScreen(mainScreen);


}//End Ctor



Create the ListField Class


Now we'll create a private ListField class and we'll override the paint() method to draw the highlight color on the selected row. The tricky part is forcing the redraw of the highlight color - you must first determine the selected row by calling getSelectedIndex() then mathematically calculate the size of the row to paint the highlight color. Here's the code (the comments are pretty detailed explaining what is going on there):


private class MyListField extends ListField{


//0,ListField.MULTI_SELECT
private boolean hasFocus = false;

public void onFocus(int direction){
hasFocus = true;
}

public void onUnfocus()
{
hasFocus = false;
super.onUnfocus();
invalidate();
}

public void paint(Graphics graphics)
{ int width = Display.getWidth();
//Get the current clipping region
XYRect redrawRect = graphics.getClippingRect();
if(redrawRect.y < 0)
{
throw new IllegalStateException("Error with clipping rect.");
}

//Determine the start location of the clipping region and end.
int rowHeight = getRowHeight();

int curSelected;

//If the ListeField has focus determine the selected row.
if (hasFocus)
{
curSelected = getSelectedIndex();

}
else
{
curSelected = -1;
}

int startLine = redrawRect.y / rowHeight;
int endLine = (redrawRect.y + redrawRect.height - 1) / rowHeight;
endLine = Math.min(endLine, getSize() - 1);
int y = startLine * rowHeight;

//Setup the data used for drawing.
int[] yInds = new int[]{y, y, y + rowHeight, y + rowHeight};
int[] xInds = new int[]{0, width, width, 0};

//Set the callback - assuming String values.
ListFieldCallback callBack = this.getCallback();

//Draw each row
for(; startLine <= endLine; ++startLine)
{
//If the line we're drawing is the currentlySelected line then draw the fill path in LIGHTYELLOW and the
//font text in Black.
if(startLine == curSelected){

graphics.setColor(Color.LIGHTYELLOW);
graphics.drawFilledPath(xInds, yInds, null, null);
graphics.setColor(Color.BLACK);
graphics.drawText((String)callBack.get(this, startLine), 0, yInds[0]);

}
else{
//Draw the odd or selected rows.
graphics.setColor(Color.LIGHTGREY);
graphics.drawText((String)callBack.get(this, startLine), 0, yInds[0]);
}

//Assign new values to the y axis moving one row down.
y += rowHeight;
yInds[0] = y;
yInds[1] = yInds[0];
yInds[2] = y + rowHeight;
yInds[3] = yInds[2];
}

//super.paint(graphics);
}
}



Create the ListfieldCallback Class


The final step is to create the private ListFieldCallback class that's attached to our ListField. Since we're not embedding images or doing other fancy things, only writing Strings to the Callback, the code is relatively straightforward, as shown below:



//Private class to populate the ListField private variable
private class ListCallback implements ListFieldCallback{


private Vector listElements = new Vector();

public void drawListRow(ListField list, Graphics g,
int index, int y, int w) {

String text = (String)listElements.elementAt(index);
g.setColor(Color.LIGHTGREY);
g.drawText(text, 0, y, 0, w);
}

public Object get(ListField list, int index) {
return listElements.elementAt(index);
}

public int indexOfList(ListField list, String p, int s) {
//return listElements.getSelectedIndex();
return listElements.indexOf(p, s);
}


public void insert(String toInsert, int index) {
listElements.insertElementAt(toInsert, index);
}

public void add(String toInsert){
listElements.addElement(toInsert);
}

public void erase() {
listElements.removeAllElements();
}

public int getPreferredWidth(ListField listField) {
// TODO Auto-generated method stub
return 0;
}



}
}



The final result will be a scrollable list that highlights the user selected option in a Light Yellow color, as shown in the screenshot at the top of this post. Once you understand how this works you can see how modifications to the overridden paint() method in ListField could permit you to have highly modifiable rows in the list - for example, in a Flikr client app you might have a scrollable list of your friends with a thumbnail on each row showing a sample picture from that friend's account. When the user scrolls to a new friend in the list (startLine == curSelected), you might initiate a function that updates the thumbnail with a changing feed of images from that user's account. The possibilities are almost infinite when customizing ListFields. I'll be on the lookout for questions in the comments section.
In order to maximize sales of your application you'll want to ensure that your code will run across all the Blackberry JDE component versions, or at minimum you'll want to write code that is portable across the most popular Blackberry phones on the market: the Pearl, Curve, Bold and Storm and the various iterations of models within each line.

The main issue outside of the complexity of managing memory and laying out the screen components is that you want to have a single manageable code base that runs across Blackberry phones so you don't have to contend with several branches of code specific for each phone. You might think that you'd simply import the appropriate Storm touch classes, code the touch interface aspects of your app, compile and run to make your existing code work for 4.7.0. The problem is that shortly after you're done you'll see that your code will run on the Storm simulator but fail miserably for anything below 4.7.0 - the 4.6.x components and below don't recognize imports of classes built for 4.7.0.

Preprocessor Directives and Definitions


So how do we take our existing code, add the touch aspects, and have it compile in 4.6.x and below? This is where preprocessor directives come into play. In standard C and Java programming, preprocessor directives are invoked by the compiler as the first part of translation. For example, #include and #define in C and import in Java. In the context of Blackberry programming, the preprocessor directives will tell the compiler to import class definitions and perform statements within our code dependent on preprocessor definitions that we set up within the Eclipse programming environment.

For our example, we will use the preprocessor directives to tell the compiler to load the TouchEvent and VirtualKeyboard classes from 4.7.x. In order to do this within the Eclipse environment we have to do a bit of a hack by using the #ifndef (otherwise known as 'if not defined') directive as if it is a #ifdef(otherwise known as 'if defined'). We'll also configure the Eclipse IDE to provide the preprocessor definition which will write the appropriate config to the .jdp RIM project file without us having to manually edit it.

Eclipse Configuration


The current iteration of the Eclipse Blackberry plugin has the capability for preprocessor definitions built in, under the project properties. The settings can be found by clicking in the Eclipse menu on Project->Properties->Blackberry Project Properties and selecting the "Compile" tab. It will look like the image below:



If your Eclipse doesn't have the 'Preprocessor Defines' box then you'll have to update your plugin version to take advantage of this feature. Click the Edit button and add the following lines:

  • JDE_4_7_0

  • PREPROCESSOR



Click the Apply button and Eclipse will clean the project and rewrite the Preprocessor defines you just added to the .jdp RIM project file. Just as a sanity check, open this file and check the 'Options' line that is near the end. It should now look like this if the changes were appropriately made:

  • Options=-define=JDE_4_7_0;PREPROCESSOR



Adding Preprocessor Directives to Your Code


Now that you've configured Eclipse with the proper Preprocessor definitions you need to add the directives to your code so the preprocessor knows what to add and when. For our example we are going to add the code necessary to perform touch events and import the appropriate 4.7.x classes. First you want to import the classes to your program file, then surround the import statement with the directives,refer to the example below:


//#preprocess
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

//#ifndef JDE_4_7_0
/*
//#endif
import net.rim.device.api.ui.TouchEvent;
import net.rim.device.api.ui.VirtualKeyboard;

//#ifndef JDE_4_7_0
*/
//#endif

import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.MenuItem;
....


We're using #ifndef statements and multi-line comments to trick Eclipse into allowing the import statements without showing errors when you don't have the 4.7 components installed. As a result these statements will appear as comments in Eclipse but will load appropriately when the JDE_4_7_0 preprocessor definition is loaded. Note that you must have the #preprocess statement at the top of any file where you're using preprocessor directives.

Within your code blocks you'll also have to use this commenting approach around any statements dependent on the 4.7 components. Refer below to the VirtualKeyboard calls within the constructor call:


public SearchScreen(Search s){


super(DEFAULT_MENU);
//Necessary because by default keyUp events are disabled
UiApplication.getUiApplication().enableKeyUpEvents(true);
search = s;
myCallback = new ListCallback();
myCallback.erase();
myList = new ListField(0,Field.FIELD_HCENTER);
ingredients = search.getIngredientList();

//#ifndef JDE_4_7_0
/*
//#endif

vk = this.getVirtualKeyboard();
vk.setVisibility(VirtualKeyboard.HIDE_FORCE);

//#ifndef JDE_4_7_0
*/
//#endif
}


Now when you want to run the code using 4.6 or lower components just delete the JDE_4_7_0 preprocessor definition from the project properties and change the installed components to 4.6 or lower. You'll find that Eclipse won't generate any errors and the code will run as intended across devices.

Epilogue


Obviously there are other issues that plague Blackberry developers when it comes to cross phone portability. One issue is that of available phone memory which determines the number of persistent/normal object handles available to your program. For a great guide on managing memory, check out the Blackberry Memory Best Practice Guide.

Secondarily, you'll have to ensure that your application layout is portable across phones since the resolution is different between models. You'll find yourself having to check the resolution of the device within your code in order to position buttons, align text boxes, etc. for each device. In other words, there will be a lot of code that checks the screen width and height to layout the screen for each device similar to the code below that sets the font size for different devices:




width = Display.getWidth();
height = Display.getHeight();

if(width == 480 || width == 360)
fSize = 21;
else if(width == 320)
fSize = 18;
else
fSize = 16;

Blackberry Code Signing - Setting up Eclipse to use Keys

During the course of development on the Blackberry platform you're bound to call functions from RIM's set of restricted APIs. The APIs with controlled access tend to be the most interesting as they touch core OS modules such as messaging, invoking the browser, access to mail, adding menu items, etc. The point of controlling access via code signing keys is you'll be interfacing with system critical functionality - RIM needs to be able to map applications to specific developers in the event your code is wreaking havok with the OS or is performing something unethical. Although the keys cost $20 US per set you should count yourself lucky to be developing on a platform where you can run your application as a background process unlike Apple app development where you're running in a sandbox. This means that you'll be able to freely add to the functionality of the phone, permitting you to extend and improve RIM' built-in features.




Restricted Blackberry APIs


When you're testing on the simulator Eclipse will give warnings that you're calling these restricted APIs but will still permit you to invoke the simulator. Ideally, you'll want to install your application on an actual phone and this is where obtaining the code signing keys come into play. Below is an overview of the Blackberry packages that require code signatures:

  • net.rim.blackberry.api.browser - gain access to the Blackberry Browser application through getDefaultSession() and getSession() functions

  • net.rim.blackberry.api.invoke - provides functionality for your application to access and invoke internal applications such as Camera, Calendar, Calculator, Maps, etc.

  • net.rim.blackberry.api.mail - interface to mail features including sending, receiving, and accessing email.

  • net.rim.blackberry.api.mail.event - interface to listener functionality for events, mail, folder changes, services, etc.

  • net.rim.blackberry.api.menuitem - permits adding and registering custom menu items to application.

  • net.rim.blackberry.api.options - add system-wide option menus for multiple applications to access.

  • net.rim.blackberry.api.pdap - if your application must conform to the Personal Digital Assistant Profile(PDAP) speification you must implement this interface.

  • net.rim.blackberry.api.phone - as the name suggests, the PhoneListener interface along with the Phone and PhoneCall classes permits access to the Blackberry Phone application to send and receive calls along with changing phone options.

  • net.rim.blackberry.api.phone.phonelogs - interface for attaching listeners to phone log events.

  • net.rim.device.api.browser.field - interface to BrowserContent (URL rendering) and events to open, close, and monitor browser fields.

  • net.rim.device.api.browser.plugin - API to add support for custom MIME types to the RIM browser.

  • net.rim.device.api.crypto - API for encryption and decryption of data, digital signing, authentication of data.

  • net.rim.device.api.io.http - provides API for request methods, header requests, and push input streams for use with TCP/IP connections.

  • net.rim.device.api.notification - API for indicating events to the user via tone, vibration, or LED as well as dialogs or interaction screens on the RIM device.

  • net.rim.device.api.servicebook - provides access to the device service book containing information that configures how the phone will interact with the enterprise infrastructure and enables specific services for the device.

  • net.rim.device.api.synchronization - interface to backup/restore both wired and over the air.

  • net.rim.device.api.system - not all system classes/interfaces require code signing keys however those that do include: interface for receiving audio events, application management(ApplicationManager), access to the backlight(Backlight), requests for the Device to power down, go into storage mode, set time and date(Device), API to access the device display properties (Display), access to store application object data on the phone (PersistentStore), and more.



Apply For Signature Keys and Install


The first step in the process is to complete the web form application including providing your credit card details and a personal 10 digit PIN number that you create. Think of it in the same way as the PIN number for your ATM card - it protects you from someone else acquiring your key and using it to sign their application. Once you submit the form, within 2 weeks you'll receive three emails from Blackberry, each containing a different client key - RBB, RRT, and RCR.

The instructions that come with the keys are comprehensive and I didn't run into trouble but I've included the Eclipse version below for reference. It is a two-step process for making a signed application. First you have to register the keys with RIM using the following process:

BlackBerry JDE Plug-in for Eclipse Users:

1) Save all 3 .csi files in the same directory (each one will be sent in a separate email message).
2) Start Eclipse.
3) Click on the BlackBerry menu and choose Install Signature Keys.
4) Select one of the 3 .csi files saved in step 1 and click Open.
5) Click "Yes" to create a new key pair file.
6) Type a password for your private key of at least 8 characters, and type it again to confirm. This is your private key password, which protects your private key. Please remember this password as you will be prompted for it each time signing is attempted or a signature key is installed.
7) Move your mouse to generate date for a new private key.
8) In the Registration PIN" field, type the PIN number that you supplied on the signature key order form.
9) In the Private Key password field, type the password created in step 6.
10) Click Register .
11) Click Exit .
12) Repeat this process for the other csi files.

One undocumented aspect of this part of the setup is that you'll have to copy the files 'sigtool.db' and 'sigtool.csk' from your main Research in Motion folder to your Eclipse plugin folder. On my system (Windows 7 64-bit) the originals were located at C:\Program Files(x86)\Research In Motion\BlackBerry JDE 4.5.0\bin and the path to the Eclipse plugin was C:\Program Files(x86)\Eclipse\plugins\net.rim.eide.componentpack4.5.0_4.5.0.164.5.0\components\bin. So long as these files are in the correct place you'll have the code signing keys installed and all warnings on use of restricted APIs within Eclipse will be eliminated within the workspace.

One Set of Keys on Multiple Machines?


Once you install the keys on your box you cannot move them to another machine without going through RIM support and requesting new keys. As I understand it, this process invalidates your original keys. The bottom line is that you cannot use one set of keys across multiple machines so chose the box where you install the keys wisely.

Request for Code Signature from Blackberry Signing Authority


The second step is to force your .cod file to be signed by requesting the code signature from the Blackberry Signing Authority Tool. This is done by navigating to the directory where your compiled application resides and double-clicking the cod file you'd like to request signing. If the install of your keys went correctly the signature tool will appear that looks like the one below:



Since the application that I'm requesting signing for is large, you'll notice that the cod file is broken into many separate parts and each must be signed. When you click request, a popup will appear asking for your private key that you set up during the first step.



Enter your password and the request will be sent to RIM's signing authority. Keep your eye on the status column of the signature tool to see if you successfully requested the signing. If you were successful, the status will show "Signed" as below:




That's all there is to it. Now you can directly provision your application and test directly on the actual hardware. An extremely valuable reference to code signing can be found here.

Blackberry User Interface Design - Build a Title Screen









I know, I know - The video embedded here shows an iPhone application and as Blackberry developers we despise the iPhone (mainly because iPhone developers have it easy developing apps for one platform with a uniform API and screen size. We're jealous) There's a point to watching that video so take a minute. Making professional Blackberry applications isn't necessarily easy given the complexity of the J2ME environment and vastness of the Blackberry API.

Lots of little tricks with the API are necessary in order to make a rich end user experience. I've found that devoting the time to designing the user interface up front is time well spent. In fact recently I read a great book called "Getting Real" written by the fantastically successful 37Signals team, most famous for creating the online project management software Basecamp and in geek circles for being the creators of the Ruby on Rails framework. I highly recommend buying the book but if it's out of reach then at mininum subscribe to the team's Signal vs Noise blog that is a wealth of design, business, and general startup information.

According to the 37Signals team, programmers should not start designing and building backend functionality first - instead they are proponents of designing the interface before you even start programming. They have a really good point that the interface is the product - it's what people see first and it's what's going to sell your app on Blackberry's app store over your competitors. It seems obvious but if two apps perform similar functionality yet one has an intuitive interface and just plain "looks pretty" it will sell in vast quantities over the less functional app. So in case you didn't get it by now, invest your time in the UI as, in my opinion, it will only benefit you in the end.

If you have any doubt about how much thought can go into the user experience on a mobile application and haven't watched it yet, take a look at the video embedded in this post demonstrating the evolution of the interface for the Convert iPhone application from initial design to final product - amazing isn't it? I have a feeling the TapTapTap team comes from the same design school of thought as the 37Signals guys.



Although "Getting Real" is focused on building web applications, 37Signals UI design philosophy of keeping features/design simple can be extended to other applications including the Blackberry. Yes, the Blackberry has a limited set of Fields for UI elements including the list below, in no particular order and with direct links to the 4.5 API documentation. I suggest you familiarize yourself with these classes and their apis even if you're a novice Blackberry dev. The beauty of these built-in classes is that they can be extended and modified and of course the paint function of any of these elements can be overridden thus, you are limited only by your imagination. In future tutorials I'll show you how to build custom Fields by extending these classes - the coding section of this tutorial will strictly center on building a title screen.



At any rate, besides coming here to read my wonderfully written prose you may have also wanted to learn how to make a title screen for your application. The title screen is important as it identifies your app with a unique look and if your app takes awhile to load, it tells the user that something is going on - otherwise the user clicks your app and proceeds to stare at the home screen while the clock/timer is displayed, something like this:





This is pretty unintuitive so one of the first things I'll do is design an eye-catching title screen with graphics that pop. It really adds to the professionalism of your app. As far as coding the title screen, it's relatively easy to write, we just have to initiate a thread that will push the title screen onto the stack and display it while the application loads. First you have to implement the Runnable interface so we can override the run function for the standard main function that creates the application and enters the event dispatcher, as follows:


public class MainScreenUI extends UiApplication implements Runnable {

public static void main(String[] args){


MainScreenUI theApp = new MainScreenUI();
theApp.enterEventDispatcher();

}
.....//more Class code here



Once this is done you'll create the run function in the main application class, in my example that's the class MainScreenUI and it's constructor is written as follows:


public MainScreenUI(){

TitleScreen ts = new TitleScreen();
pushScreen(ts);
Thread t = new Thread(this);
t.start();


public void run(){
Application.getApplication().invokeLater(new Runnable()
{
public void run()
{
FirstScreen fs = new FirstScreen();
pushScreen(fs);
}
});


So what's going on here? Essentially, MainScreenUI is created in the main() function. the constructor for MainScreenUI is called and it pushes an instance of the TitleScreen (not shown) onto the display stack - TitleScreen is simply a class that extends FullScreen and draws our titlescreen bitmap we've designed in Photoshop, Illustrator, or InkScape via the overridden paint function. We create a Thread named t and start it by calling the start() function.

The thread performs whatever functionality we've designed into the run() function above. In the example we create a new Runnable and add it to the stack of threads to be invoked by the Application - here it's Application.getApplication.invokeLater(...) and we're overriding both the MainScreen run() and the Application run() methods. An instance of our main application entrypoint, FirstScreen(not shown), is created and then is pushed onto the display stack once complete. If your application loads quickly you may want to add a sleep(x) function(where x is some numeric value to wait) before creating the main application screen to give the user time to at least see the titlescreen.

As you can see it's relatively painless but does add some flash to your app.

Blackberry Simulator is a Time-Burglar?


Blackberry has done an excellent job designing the Blackberry simulators that come with the Eclipse plugin. Testing and debugging is really a breeze once the simulator is running. The only problem I have with the tools that Blackberry supplies is the length of time it takes for the simulator to start. I'm not running the tools on a slow machine either - My setup is a new Mac Mini - 2 GHz Intel Core 2 Duo - with upgraded 7200RPM hard drive and 4GB of RAM, running Windows 7 64-bit in the Bootcamp partition. Although I have VMWare fusion on Leopard, I still boot directly into Windows 7 since Fusion seems to run Win7 pretty slow.

I timed the startup of the simulator and it takes a full 35 seconds to boot the device to the home screen while it takes 55 seconds with the debugger attached. Unfortunately, you cannot load changes to the code dynamically into the simulator - at least I haven't been able to find a way to do this. So you know what this means - every time you want to test your code you have to wait 35-55 seconds for the simulator to start then locate your program in the device and click it to run.

To make matters worse, the close button on the simulator doesn't function and you cannot easily start a new simulator when one is running. The only solution is to keep the Windows task manager open at all times and use it to shut the simulator down. I did some investigation when I first started programming for Blackberry and haven't found a solution for this issue anywhere.

It may seem that I'm complaining about something minor but when you stop and think about the time waste of sitting and waiting for the simulator to start over the course of developing an app, those chunks of 35-55 seconds really start to add up. While programming it's common for me to run the simulator 5-10 times an hour. Staying on the conservative side, lets say 5 times an hour - 5 x 35 /60 means you're wasting almost 3 minutes each hour sitting and waiting for the simulator to start. Multiply this x 10 hrs of work each day means 30 minutes of your time is wasted each day doing nothing - just twiddling your thumbs waiting for the simulator.

Given these estimates, I'd say that on the last application I wrote a full day(24 hours) was wasted waiting for the simulator and that's not even counting the extra time it takes for the debugger to start! The only thing you can do to speed up startup each time is to escape the Setup Wizard when you first run the simulator of choice, or for every simulator you use. This will prevent the Wizard from running saving you a few seconds. Unfortunately, my timing of startup includes this "optimization" so don't expect anything faster.
top