I/O Read Performance on Android 2.2

I’ve been experimenting with an app prototype that I hope to release on the Android market soon. The app reads sizable files (few hundred KB to a several MB) containing thousands of records. The app is a viewer for those records.

When the app initializes, it makes a pass through the file to index it which will eventually provide the UI layer with the ability to paginate through the file. When indexing, I find the boundaries of each record, and built up a data structure containing the offsets. This part of the read must be very fast, and uses a sequential reading pattern to read the entire file.

I started to notice some performance problems with this approach, so I decided to investigate performance of 3 common I/O methods. I don’t consider this a perfectly optimized benchmark, but it is an apples-to-apples comparison with the code I wrote. I’m posting these performance results in case other Android developers are trying to figure out which I/O method to use. Being new to Java in general, I wasn’t sure what was the best approach.

The first method of reading bytes from this file was done through a DataInputStream. It was initialized like this:

fin = new FileInputStream(new File(this.fileName));
din = new DataInputStream(new BufferedInputStream(fin));

Data was read using methods such as readInt(), readShort(), etc.
The second method was to use a RandomAccessFile stream. This type of stream was new to me, and was of interest because of the ability to access a file in random places. Although the first type of parse operation does not require random access, the second type of operation will benefit from this. The stream was initialized like this:

rin = new RandomAccessFile(this.fileName, “r”);

The third type of method was coupling a RandomAccessFile stream with a MappedByteBuffer. From reading the Android SDK, it appeared that there might be some advantages to this approach. The file is just mapped into a section of memory in the JVM, and other processes are able to access (and even write to) the file. It was initialized like this:
rin = new RandomAccessFile(this.fileName, “r”);
MappedByteBuffer buffer = rin.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, rin.length());
After implementing all 3 versions of these streams, in such a way that they can be switched around very easy, I ran performance tests on files ranging from 500 to 10000 records. I took 5 runs through the test collateral, and averaged the results.

Environment

  • HTC EVO
  • Android 2.2 (Froyo)

Performance

Conclusions

The DataInputStream method of reading sequentially from a binary file was roughly twice as fast as the RandomAccessFile and MappedByteBuffer methods. I think for my initial indexing of the file, the DataInputStream method will work the best. When I implement the random access capability for pagination, I’ll need to revisit this with further benchmarks that expose that behavior.

Leave a Reply