Coding for Speed

Team-Fly

Small devices have small, relatively slow processors. Part of your task as a developer is ensuring that your application runs fast enough that users won't reject it.

Optimize Loops

One simple optimization has to do with looping. A typical loop through a Vector v might look like this:

 for (int i = 0; i < v.size(); i++) {   Object o = v.elementAt(i);   // Process the Object o. } 

Each time through the loop, v's size() method is called. An optimized version would store the size of the vector first, like this:

 int size = v.size(); for (int i = 0; i < size; i++) {   Object o = v.elementAt(i);   // Process the Object o. } 

This is a simple example, but it illustrates that loop conditions are one place you can look for speed optimizations.

Use Arrays Instead of Objects

Arrays are usually faster and leaner than collection classes. We touched on this theme earlier in our discussion of Strings and StringBuffers; if it's not too clumsy, using character arrays directly will probably be more efficient than dealing with String and StringBuffer objects. The same rule applies to the MIDP collection classes Vector and Hashtable. Although Vector and Hashtable are simple and convenient, they do impose some overhead that can be trimmed. Vector is basically just a wrapper for an array, so if you can work with an array directly, you'll save yourself some memory and processing time. Similarly, if you have a simple mapping of key objects to value objects, it might make sense to use object arrays instead of Hashtable.

If you do decide to use Hashtable or Vector, try to size them correctly when you create them. Both Vector and Hashtable grow larger as needed, but it is relatively expensive. Vector creates a new internal array and copies elements from the old array to the new array. Hashtable allocates new arrays and performs a computationally expensive operation called rehashing. Both Vector and Hashtable have constructors that allow you to specify the initial size of the collection. You should specify the initial size of these collections as accurately as possible.

If you are using the persistent storage APIs, you may be tempted to wrap stream classes around the record data. For example, you might read a record, then wrap a ByteArrayInputStream around the record's data, and then wrap a DataInputStream around the ByteArrayInputStream to read primitive types from the record. This is likely too heavy to be practical. If at all possible, work directly with the record's byte array.

Use Buffered I/O

Don't read bytes one at a time from a stream, and don't write them out one at a time. Although the stream classes provide methods that read and write a single byte, you should avoid them if at all possible. It will almost always be more efficient to read or write a whole array full of data.

J2SE provides BufferedReader and BufferedWriter classes that provide buffering functionality "for free." There is no such luxury in the MIDP universe, so if you want to use buffering, you'll have to do it yourself.

Be Clean

One simple piece of advice is to clean up after yourself. Releasing resources as soon as you are done with them can improve the performance of your application. If you have internal arrays or data structures, you should free them when you're not using them. One way to do this is to set your array reference to null so the array can be garbage collected. You could even call the garbage collector explicitly with System.gc() if you're anxious to release memory back to the runtime system.

Network connections should also be released as soon as you're done with them. One good way to do this is to use a finally clause. Consider the following code, which does not use a finally clause:

 HttpConnection hc = null; InputStream in = null; try {   hc = (HttpConnection)Connector.open(url);   in = hc.openInputStream();   // Read data from in.   in.close();   hc.close(); } catch (IOException ioe) {   // Handle the exception. } 

The problem occurs if an exception is thrown while you're trying to read data from the connection's input stream. In this case, execution jumps down to the exception handler, and the input stream and connection are never closed. In a J2SE environment, with memory to burn, this is probably not a big deal. But on a MID, a hanging connection could be a disaster. When you absolutely, positively want to be sure to run some code, you should put it in a finally block like this:

 HttpConnection hc = null; InputStream in = null; try {   hc = (HttpConnection)Connector.open(url);   in = hc.openInputStream();   // Read data from in. } catch (IOException ioe) {   // Handle the exception. } finally {   try {     if (in != null) in.close();     if (hc != null) hc.close();   }   catch (IOException ioe) {} } 

This is starting to look a little ugly, particularly the try and catch inside our finally block. A cleaner solution would be to enclose this code in a method and declare that the method throws IOException. This cleans up the code considerably:

 private void doNetworkStuff(String url) throws IOException {   HttpConnection hc = null;   InputStream in = null;   try {     hc = (HttpConnection)Connector.open(url);     in = hc.openInputStream();     // Read data from in.   }   finally {     if (in != null) in.close();     if (hc != null) hc.close();   } } 

The deal with finally is that its code gets executed no matter how control leaves the try block. If an exception is thrown, or if somebody calls return, or even if control leaves the try block normally, our finally block still gets executed. Note that there is still small room for trouble here: if an exception is thrown when we try to close in, then hc will never be closed. You could enclose each close() call in its own try and catch block to handle this problem.

Optimize the User Interface

It's important to remember that you are trying to optimize the perceived speed of your application, not the actual speed of the application. Users get fidgety if the application freezes up for a few seconds; adding some sort of progress indicator can go a long way toward making users happier. There's really nothing you can do to make the network run faster, but if you display a spinning clock or a moving progress bar, your application will at least look like it's still alive while it's waiting for the network.

Keep in mind that users of mobile phones and other small "consumer" devices will be much more demanding than typical desktop computer users. Through years of experience, bitter desktop computer users have fairly low expectations of their applications. They realize that most desktop applications have a learning curve and are frequently cantankerous. Consumer devices, on the other hand, are much more likely to work right the first time, requiring neither manuals nor advanced degrees to operate.

With this in mind, be sure that your MIDlet user interface is uncomplicated, fast, responsive, and informative.


Team-Fly


Wireless Java. Developing with J2ME
ColdFusion MX Professional Projects
ISBN: 1590590775
EAN: 2147483647
Year: 2000
Pages: 129

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net