http://www.developer.com/java/ejb/article.php/3526721/Building-a-J2ME-Application-in-NetBeans-41.htm
This article will show you how to use NetBeans 4.1 and the Mobility Pack to write a Java Mobile Edition application quickly and easily. It will demonstrate the simple GUI creation and storage facilities available to a mobile application developer, but will not delve into the online connection capabilities at this point (I will instead save that for the future). The application I will demonstrate will be a simple vehicle mileage calculator and tracker, allowing you to use a mobile phone or other Java-enabled device to track your average fuel consumption and cost per mile. It is deliberately kept simple and I will note any simplifying assumptions made as the application is presented. It is, of course, entirely up to you if you want to extend this code into something more detailed and useful. The toolset used for this demonstration is NetBeans 4.1 with the Mobility Pack, both of which are freely available for download from http://www.netbeans.org. The full project source for this article is available for download from this link. Before you can start building the application, you will need to get NetBeans 4.1 and the Mobility Pack if you don't already have them. Both the NetBeans IDE and the Mobility Pack can be downloaded from http://www.netbeans.info/downloads/download.php?type=4.1. Optionally, enter your e-mail address or uncheck the checkboxes, and click Next to get to the download area. Be sure to read the Installation Instructions and Mobility Pack release notes using the links on the download page. The core of our application will be a visual MIDlet, which can be thought of as a visual JavaBean for a phone. In fact, this is selling it shortthe MIDlet encompasses multiple forms and other GUI views, navigation information between these GUI parts, lifecycle methods for the application, as well as the usual event handlers, methods, and properties. To create your MIDlet, do the following: You should now find yourself looking at the flow designer. There should be an icon that looks like a phone, with a Start Point and an Exit Point. This is one view of the MIDlet; there are two more selectable by buttons at the top of the main pane: Screen Design and Source. Click the Source button to see what is already in the MIDlet at present. You should see a default constructor (empty) and three lifecycle methods: startApp(), pauseApp(), and DestroyApp(). I will come back to these later. The first part of your application building will be the GUI. There will be three screens in your application. The "main" screen will be the summary pagewhere you can see the current mileage, MPG, and cost information summarized. There will also be menu options from this screen to the two others you needan initial setup screen (to enter the vehicle's mileage when you first start using the calculator) and a screen to enter new details when you fill up. The summary page will simply give you a run down of the current details for your vehicle, including the current recorded mileage, the current MPG, and the cost per mile since you started keeping records. To create the summary page: So far, so good (and nice and easy). You should now see an empty screen ready to take new widgets from the pallette (to the left of the empty form). Before you start adding components, I will take the chance to talk about GUI design in Java ME, and how it compares with desktop applications. If you have designed a full swing GUI, you will notice some differences when using Java ME to create screens. The most obvious is that there are fewer components. Not so obvious, however, is that (at least for what we are doing) you cannot control the layout of the components as much as you might be used to in swing. The concept of different layout managers does not exist in this GUI builder, nor does it make sense if you stop and think about it. When designing for a mobile device, you are likely to be dealing with any number of different screen sizes and configurations. Generally speaking, a Java ME application will use all of the screen, not a window within that screen, so that means that the application could be displayed at any resolution from fairly small (say 100x100 pixels for the sake of argument) up to much higher resolutions. When you think about this, it makes sense that trying to control layout would be very hard. In fact, the device will largely control the layout based on what makes sense to it. I will put down the components you want in the order you want (using a simple flow layout for you Swing folks out there), and leave it to the device to figure out the display details. Although it may feel a bit strange at first, this model of development is actually quite liberating after you get used to it, and you can certainly slap some GUIs together pretty fast. They might not win any beauty prizes, but they will be functional and they will work on any device (although if you pack a lot onto one screen, you might find yourself scrolling around a lot when running on lower-resolution devices). The "device handles it" philosophy is carried over even further for the action items (like the menu). You will define the menu actions you want, and the device will figure out how to present them to the user. The likelihood is that the options will be attached as a menu on one of the device's "soft buttons," but it really is down to the device on which the application is running. To add the components to your summary screen, follow these steps: Once you have completed these steps, you can run the application to see what it looks like. It won't do anything except show the screen you have created, but you will get to see your application run for the first time, and get an idea of how the emulator works. Click the debug button in the toolbar; after a few seconds, a window containing a picture of a phone should appear. You should see MileageMidlet highlighted in the menu, and a label saying "Launch" over the right softkey of the phone. Click the softkey and you should see your new screen appear. When finished, close the window (or choose exit from the menu). You may need to do this twice because the first time will quit your app, and the second will quit the emulator. Although it will probably only be used once for your application, you need a page to set up the initial mileage on the vehicle when you start using it. This screen should show a reminder to only initialize the mileage after the vehicle has been filled with Gas (otherwise, the initial calculations will be thrown off). It should also allow the user to enter the current mileage, and reset all of the other totals to 0. Don't worry about the action code behind the scenes. You will write all that in a moment. Finally, we need a new page to add details when you add fuel to the vehicle. This page should take the current mileage of the vehicle, along with the number of gallons and the cost of the gas: Okay, you now have your three screens in the application, but no way to get between them, not to mention that there is no code at all to do anything useful. First, hook up the screens: Setup for navigating between screens is accomplished from the Flow Design view, so switch back to that. Actions and navigation in a Java ME app are accomplished by creating commands, and then hooking those commands up to code and navigation events. This will make more sense after you have added a command. The first command you will add to the summary page will be to add new details. This will be the default action, because it is the most likely thing you will want to do with your application. There are hints you can give to the device about this being a default, even though you can't directly control how the device will make the option available. In your case, you will add this command as an "OK" command in the hope that it will get a soft button of its own (again, this will be up to the device, but hopefully this hint will help). To create your Add Details command: You also want to get back to the main summary form from your details form, and there are two ways you might want to do this. One is to enter details and click OK, whereupon the totals and averages of the summary are updated; the other will be to cancel out of the screen (if you hit it by accident), in which case you should return without making any changes. To add these two cases: Finally, you still need to hook up the Initialize screen: Okay, the navigation part of your application is set up. Start up the debugger again, and try navigating between the various screens. Even though the app doesn't do anything yet, you can see it taking shape. Here is what my Flow Design looks like after adding the above navigation: You are getting close now, but you have two major items left to add. The first is the functionality—updating the totals, doing the calculations, displaying the results, and so forth. The second equally important one is to store and load the data. When you shut down your mileage calculator, you don't want to lose the data, so it has to be stored in the device memory somewhere. Add the functionality code first, and then worry about persisting the data afterwards. The first thing you need in your application is some fields to store the data, both the totals and the averages: Note that all the fields are added as long, not float. This is because in CLDC 1.0, floating point is not a part of the spec. You will be using fixed-point arithmetic to 2DP of accuracy for this example. You can use CLDC 1.1 in your project spec, which includes floating point support, but make sure your device supports it (my series 40 Nokia does not). The solution using fixed-point arithmetic is to make some simplifying assumptions. For example, you will deal only with whole miles for the mileage (this will even out over time because you enter the vehicle's current mileage, not the difference since the last re-fuelling. Secondly, you will assume that the gallons and cost are entered using hundredths of gallons (with no decimal point) and in cents. In other words, instead of entering 12.43 gallons, you will enter 1243; and instead of $20.98, you will enter 2098. This makes it easier to type in using the phone keypad, and also keeps things nice and easy to manipulate in integers. When you calculate the summaries for the summary screen, you will use integer division and modulo to show the formatted gallons with two decimal places of accuracy. Still with me? Yes, this is a compromise, but the art of writing Java ME applications involves a fair amount of compromise. Alternatives would be to allow a string to be entered into the numeric fields, then parse out the integer information from that, or use CLDC 1.1 and go for full floating point (just watch that you have support from your target devices). Either way, these are left as an exercise for the reader for the sake of brevity. Okay, so you now have your fields. You can add some functionality to use them: Next, you need to fill in the Initialization code. This is quite simple now that you have done the above work: Okay, that's the functionality in place; as simple as it is. You can now debug the app again and try it out. Initialize it with a starting mileage and then add some details. Pretend you have filled up after 300 miles or something. You should see the summary details update when you OK the new details. Don't forget to enter gallons multiplied by a factor of 100 (1243 for 12.43 gallons) and cost in cents (2065 for $20.65). There is, however, one last missing piece. When you quit the app right now, all data is lost. You need a way to persist it. Fortunately, the persistence mechanism provided in Java ME is dead simple. The persistence mechanism you will be using is based around a RecordStore. The record store has a name assigned to it—something you choose for your application that hopefully will not clash with another one. You will call yours MileageCalcStore. Records within the record store have a numeric index, and are simply an array of bytes. You will add two new methods to your class: saveCurrentState() and loadCurrentState(). For brevity, I will simply include the code here and discuss it below: Some notes on the above: Now, you also need the code to load the values back in: This code should make sense if you understood the store code; it is basically a reversal of the store functionality. Strings are re-constructed from the byte arrays, and then parsed into the longs. Finally, the averages and summary update method are invoked, to get everything in sync. So, now you have methods to save and load the data, but you are not calling them anywhere. You could choose to call the save method whenever the initialize or add details methods are used, and load on startup. I usually choose to put the save methods into the pauseApp and destroyApp lifecycle methods instead: Save and debug the app again. This time when you run it, you can exit the application (in the phone emulator) and then restart it again, and your current totals and averages should still be there. Note that if you actually close the emulator itself and restart it, your numbers will be lost; but the main thing is that it will store permanently on your device. Once you are happy with your application, it's time to get it onto a device. This requires the construction of a jar and jad file for the application. The jar file is the packaged executable, and the jad describes it to the device, so these two normally go in combination. Fortunately, the NetBeans mobility pack makes it really easy to package up the application into these files. Simply right-click on the MileageCalculator project and select Deploy Project. This seems to give an error about a missing ant property, and I need to look into why this is (update in a later article). However, even in spite of this, the jad and jar files are created in the dist directory of the project home anyway and are ready to deploy to your device, so just pick them up from that directory. As to actually getting them onto your device, there are numerous ways to do this. One is to put the jad and jar files out on a Web server and then browse to the jad file using WAP on your phone (that is probably the most universal way to do it, assuming you have WAP access on your phone). Alternatively, you may find that your phone or other device came with software, or has software for download, that will let you install the application. For example, the Nokia PC suite, a free download from nokia.com, lets me load applications directly onto my series 40 device. In this article, you have put together a simple and not particularly pretty mileage calculator that should be able to run on any Java-enabled phone or other device. The application has illustrated the main points of Java ME development apart from online communication (which I hope to cover in a future article). The mileage app might be useful in its current form, but probably would be better if extended and improved. I hope this demonstrates that Java ME application development is easy, particularly with NetBeans and the Mobility Pack. I also hope this spurs more people to create applications that I can use on my phone. :) Dick Wall is a Lead Systems Engineer for NewEnergy Associates, A Siemens Company based in Atlanta, GA that provides energy IT and consulting solutions for decision support and energy operations. He can be reached for comment on this and other matters at dick.wall@newenergyassoc.com. He also co-hosts the JavaCast, a podcast devoted to Java news and the Java community, which can be found at http://javacast.thepostmodern.net.
Building a J2ME Application in NetBeans 4.1
August 11, 2005
Getting Started
Create a New Project
Create the Visual MIDlet
Creating the GUI
The Summary Page
Note: the "cost per mile" is simply what the gas is costing.If you want to track maintenance and other items, this application could easily be augmented to do so.
Note: If you have a particular device in mind (let's say your phone) and know the resolution, you can right-click on the screen in the Screen Designer, select "Set Screen Size," and then set it to the desired resolution. Although this won't guarantee what it will look like on your device, it will give you a better idea of how much information you can fit on the screen.
Adding the Components

Click here for a larger image.
The Initialize Page
The Add Details Page
Setting up Screen Navigation

Click here for a larger image.
Adding the Rest
Adding the Functionality
Note: Alternatively to the above, if you prefer you could simply jump straight to the source and create the new method by typing it in there. It might be quicker.
this.currentMileageVal =
Long.parseLong(this.currentMileage.getString());
int currentGallons =
Integer.parseInt(this.gallons.getString());
int currentCost = Integer.parseInt(this.cost.getString());
// figure out new totals
this.totalMileageVal = this.currentMileageVal
- this.startingMileageVal;
this.totalCostVal += currentCost;
this.totalFuelVal += currentGallons;
this.recalcAveragesAndUpdateSummary();
public void recalcAveragesAndUpdateSummary() {
// fixed point arithmetic - keep everything multiplied
// by a factor of 100
// Need to protect against division by 0
if(this.totalMileageVal == 0) {
this.avgCostVal = 0;
} else {
this.avgCostVal = this.totalCostVal
/ this.totalMileageVal;
}
if(this.totalFuelVal == 0) {
this.avgMpgVal = 0;
}
else {
// Note: 10000 multiplier is to take into account Fuel
// 100 multiplier and another 100 to add 2 DP to average
this.avgMpgVal = (this.totalMileageVal * 10000)
/ this.totalFuelVal;
}
// Temporary String to hold formatted values
String tempFormat = null;
// set the current mileage just by converting to String
this.totalMileage.setText(Long.toString(
this.currentMileageVal));
// For avg cost - format as 23 cents
tempFormat = Long.toString(this.avgCostVal) + " cents";
this.avgCostPerMile.setText(tempFormat);
// and fixed point also for MPG
tempFormat = Long.toString(this.avgMpgVal / 100) + "." +
Long.toString(this.avgMpgVal % 100);
this.avgMpg.setText(tempFormat);
}
public void initializeTotalsAndAverages() {
this.startingMileageVal =
Long.parseLong(this.startingMileage.getString());
this.currentMileageVal = this.startingMileageVal;
this.totalMileageVal = 0;
this.totalCostVal = 0;
this.totalFuelVal = 0;
this.recalcAveragesAndUpdateSummary();
}
Adding Persistence
public void saveCurrentState() {
RecordStore myStore = null;
try {
myStore =
RecordStore.openRecordStore("MileageCalcStore", true);
int n = myStore.getNumRecords();
// create the byte array representations for storing
byte[] startingMileageBytes =
Long.toString(this.startingMileageVal).getBytes();
byte[] currentMileageBytes =
Long.toString(this.currentMileageVal).getBytes();
byte[] totalFuelBytes =
Long.toString(this.totalFuelVal).getBytes();
byte[] totalCostBytes =
Long.toString(this.totalCostVal).getBytes();
// do we already have a record set to use?
if(n == 0) {
// no - create new records
myStore.addRecord(startingMileageBytes, 0,
startingMileageBytes.length);
myStore.addRecord(currentMileageBytes, 0,
currentMileageBytes.length);
myStore.addRecord(totalFuelBytes, 0, totalFuelBytes.length);
myStore.addRecord(totalCostBytes, 0, totalCostBytes.length);
}
else {
// use existing records
myStore.setRecord(1, startingMileageBytes,
0, startingMileageBytes.length);
myStore.setRecord(2, currentMileageBytes,
0, currentMileageBytes.length);
myStore.setRecord(3, totalFuelBytes,
0, totalFuelBytes.length);
myStore.setRecord(4, totalCostBytes,
0, totalCostBytes.length);
}
}
catch(Exception ex) {
// omitted for brevity - but you should do something
// with this
}
finally {
if(myStore != null) {
try {
myStore.closeRecordStore();
}
catch(Exception ex) {
// ignore
}
}
}
}
public void loadCurrentState() {
RecordStore myStore = null;
try {
myStore = RecordStore.openRecordStore("MileageCalcStore", true);
int n = myStore.getNumRecords();
if(n == 0) {
// if no record set, use safe values
this.startingMileageVal = 0;
this.currentMileageVal = 0;
this.totalFuelVal = 0;
this.totalCostVal = 0;
}
else {
String startMile, currentMile, totCost, totFuel;
startMile = new String(myStore.getRecord(1));
currentMile = new String(myStore.getRecord(2));
totFuel = new String(myStore.getRecord(3));
totCost = new String(myStore.getRecord(4));
// now parse out the values
this.startingMileageVal = Long.parseLong(startMile);
this.currentMileageVal = Long.parseLong(currentMile);
this.totalMileageVal = currentMileageVal
- startingMileageVal;
this.totalFuelVal = Long.parseLong(totFuel);
this.totalCostVal = Long.parseLong(totCost);
}
}
catch(Exception ex) {
// TODO: do something with exception (ommitted for brevity)
}
finally {
if(myStore != null) {
try {
myStore.closeRecordStore();
}
catch(Exception ex) {
// ignore
}
}
}
// now update the averages and summary
this.recalcAveragesAndUpdateSummary();
}
this.loadCurrentState();
this.saveCurrentState();
Getting the App onto a Device
Conclusion
About the Author