February 1, 2010

few notes on Samsung's IO

J2ME implementation on new Samsung phones has a few peculiarities. Yes, they're doing everything right by the spec - but they do it just slightly differently than most of the others.

First of all, InputStream.read() method, the one that reads single character, seems to be rather slow. When you say something like:
while (true) {
int ch = istream.read();
if (ch == -1) throw new IOException ("end of stream");
if (ch == '\n') break;
}

then the phone will do what you want, ssssssssllllllllllloooooooooowwwwwwwwwwwwllllllyyyyyyy.
Instead, make use of InputStream.available(), for example like this:
int av = istream.available();
if (av > 0) {
byte[] buf = new byte[av];
istream.read(buf);
} else {
int ch = istream.read();
}
The else is there for a reason. Two reasons, actually. First, some phones won't tell you what is available. So you should try to read anyway. Second, if nothing is actually available at that moment, read() will block and hopefully provide opportunity for other threads to run. (That is, if your phone implementation isn't completely retarded. Which, unfortunately, some can be.)

Now you've seen how Samsung reads from streams in large chunks. As it turns out, the chunks aren't as large as they could be.
Let's say you want to read a chunk of data from a file. Consider this:
DataInputStream dis = filehandle.openDataInputStream();
int length = dis.readInt();
byte[] buf = new byte[length];
dis.read(buf);

Can you spot the problem? Of course, the read(byte[]) method doesn't guarantee that it fills the buffer. But interestingly enough, on a vast majority of phones, it will actually do that when you're reading from a file.
Not on a Samsung.
So remember, kids, always check the return value of read(...) calls. Or, if you're using DataInput, as shown here, just readFully(...).