views:

85

answers:

2

First off - I haven't had much experience with Java yet, and I'm a beginner when it comes to the Android SDK.

I'm trying to write a music player app, which when started scans the entire SD card for mp3 files.

Currently this is how I'm doing that:

// Recursively add songs in a directory
public void addSongsInDirectory(File dir, String filter) {
    File[] files = dir.listFiles();
    if (files != null) {
        for  (File f : files) {
            if (f.isDirectory()) {
                addSongsInDirectory(f, filter);
            } else {
                // Create new MimetypesFileTypeMap
                MimetypesFileTypeMap mtfm = new MimetypesFileTypeMap();
                // Add the mp3 mimetype
                mtfm.addMimeTypes("audio/mpeg mp3");

                // If current song is audio/mpeg, add it to the list
                if (mtfm.getContentType(f).equals(filter)) {
                    songs.add(f.getName());
                }
            }
        }
    }
}

Unfortunately, on my handset with many songs on it, this process takes about 30 seconds. How can I optimize this function so that it works faster (and possibly in the background)?

+1  A: 

I don't know that this is specific to Android, but this is how I've seen other music players handle this.

The first time your app is used, you let the user know that you have to index his music collection. People expect that this will take a while.

Once you've saved an index file, you can show the index file on start up. While the user is doing other things, you index the music collection in the background. Save the new index file if it's different than the old index file.

Finally, you give the user the option of indexing his music collection anytime he wants. Usually, that's when he knows he's added a new song or two.

You would build the index file using a Java thread spun off of the UI thread.

Gilbert Le Blanc
I thought about that too, but the default Music player never asks to index files. I add new files to the SD card, open the Music app, and they're there. Also, after deleting all user data for the Music app, it takes only about 5 seconds to list all 520 files. So there must be a much more efficient method than the one I'm currently using.
danilo
@danilo: I'm guessing a thread off the UI thread. Hopefully, you'll get more android specific answers.
Gilbert Le Blanc
+3  A: 

An Android specific optimisation is to look for a file called .nomedia in a directory. This is an indication that there are no media files in a directory in any of its subdirectories. The idea is that applications can create a .nomedia file in their data directories to tell media applications that there's no need to scan them because there's no media in there (or possibly there are media files which are only used internally by the application, such as music from a game).

Alternatively, you could skip writing your own scanner and use the Media Scanner built in to Android. It's simply a matter of querying the appropriate ContentProvider.

Your code will look something like this:

String[] projection = new String[] {
    MediaStore.Audio.Media.ALBUM,
    MediaStore.Audio.Media.ARTIST,
    MediaStore.Audio.Media.TITLE
};

Cursor cursor = managedQuery(
    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, //URI
    projection, //columns to return
    null, //rows to return -  all
    null, //selection arguments - none
    null // sort order - default
);

cursor.moveToFirst();

while(! cursor.isLast()) {
    Log.d("MediaTest","Found track:");
    Log.d("MediaTest","Album " + cursor.getString(0));
    Log.d("MediaTest","Artist " + cursor.getString(1));
    Log.d("MediaTest","Track " + cursor.getString(2));
    cursor.moveToNext();
}
Dave Webb
Thanks for the hint.
danilo
Thanks for the edit, this is great as it also solves the problem with reading ID3 tags :)
danilo
Sorry for the triple comment, but for some strange reason the emulator does not find the media files on the sd card. They're not even shown in the official Music app, even though they're on the card (I can see them with a file explorer). The same piece of code works on the real phone though. Do you know what the problem could be?
danilo
I had this same issue 9I am also working on a media player). You have to empty the cached data in the emulator. It doesn't look to me like there is an option for it in donut or above but in 1.6 you can do it... and that triggers the media scanner.
androidworkz