Friday, October 06, 2006

Image.createImage throws an IOException on Sprint CDMA Phones

Carrier: Sprint
Network: CDMA
Manufacturer: Sanyo
Programming Language: J2ME


I ran into an issue trying to download jpg data to a J2ME application recently, and I figured it warranted a blog post. 

The data the comes over the air is a bunch of meta data about the image, followed by all the bytes that are the contents of the image.  When the request comes in I find where the Image starts and try to load it into an Image object.  The Image object has a method:

Image.createImage(byte[] buffer, int start, int length)

which is perfect.  I figured I could just pass in the whole response with the right start index and length, and it would work perfect.  When I tested it, it worked great on IDEN phones, and some sprint phones, but on a number of them, Sanyo phones in particular, it would only work a small fraction of the time.  Most of the time it would return a IOException with a null message. 

After debugging this for a few hours, I found that the data being sent from the server was being received right by the phone, and that the phone was using the correct start index and length.  Then I found that if the same contents were sent to two different phones, one would work and one would fail.  I couldn't figure out why it would fail, and it really didn't make any sense.

Fortunately I was able to come up with a workaround that I haven't seen on the Internet yet, hence this blog...

Instead of passing in the whole buffer, with start and length values, I just the image bytes into a new array and pass in 0 for start and the length of the array for the length.

This solved the problem, but blew my mind.  :) 

Original Code that crashed:

                     Image img = null;
                     try {
                        img = Image.createImage(output, imageStartIdx, length)
                     } catch(Exception e) {
                        throw new Exception("The map returned was not valid.");
                     }

After The Fix:

                     byte[] imageBytes = new byte[length];
                     System.arraycopy(output, imageStartIdx, imageBytes, 0, length);
                    
                     Image img = null;
                     try {
                        img = Image.createImage(imageBytes, 0, imageBytes.length);
                        // img = Image.createImage(output, imageStartIdx, length)
                     } catch(Exception e) {
                        throw new Exception("The map returned was not valid.");
                     }

This is nothing too impressive, but I figured someone might not figure it out on their own, so there it is...

Happy Coding!