Monthly Archives: November 2010

Open File Dialog in Android

Android Open File BrowserThe Android SDK does not have a file browser dialog for use by app developers. ¬†For my app MoPhotos, I needed to allow the user to select a file from their Android system that my app can use. I was surprised to learn there is no real built-in file chooser dialog. From my experience with .NET and the Win32 API, that’s a function that you can count on being there. I did not think it would be difficult to write one myself, but I’m always looking for quicker ways to get there.

Eventually, I found a blog post by Android-er, who shows a very simple version of the mechanics behind a file open dialog. After getting my version of his code up and running, I wanted to make a few modifications to meet my needs. These modifications are:

  • Alphabetize the list of files
  • Exclude hidden files, hidden directories, and directories without read access
  • Only show files with compatible file extensions

Fortunately, this was very easy to do using standard Java API’s. Instead of calling:

File[] files = f.listFiles();

I create a FileFilter to filter out the results:

File[] files = f.listFiles(new FileFilter() {
  @Override
  public boolean accept(File pathname)
  {
    //If a file or directory is hidden, or unreadable, don't show it in the list.</div>
    if(pathname.isHidden())
      return false;
    
    if(!pathname.canRead())
      return false;

    //Show all directories in the list.
    if(pathname.isDirectory())
      return true;

    //Check if there is a supported file type that we can read.
    String fileName = pathname.getName();
    String fileExtension;
    int mid= fileName.lastIndexOf(".");
    fileExtension = fileName.substring(mid+1,fileName.length());
    for(String s : supportedFileExtensions) {
      if(s.contentEquals(fileExtension)) 
        return true;
    }

    return false;
  }
});

The last change was to sort the files and directories alphabetically. I do the sorting operations after the list is constructed, but before the ArrayAdapter is initialized.
//Sort the files alphabetically.
Collections.sort(fileStringList);
Collections.sort(pathStringList);

fileListAdapter = new ArrayAdapter(this.getContext(), R.layout.open_file_entry, R.id.fileName, fileStringList);
ListView lv = (ListView) this.findViewById(R.id.pcap_files_list);
if(lv != null)
{
  lv.setAdapter(fileListAdapter);
}

So far, this code is working as intended. I don’t know if this is the most-optimal to do this, but that will be analyzed before I release this app to the market. For now, I’m still building out the basic infrastructure.

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.