Billie Holiday

Figure 5-3. Albums listed in basic ListView

To allow the user to actually select one of the albums, we need to override the default onListItemClick method that is provided by our ListActivity parent class.

protected void onListItemClick(ListView l, View v, int position, long id) { if (currentState == STATE_SELECT_ALBUM) {

When an album in the list is selected, this method will be called. Since our currentState variable starts off as STATE_SELECT_ALBUM the first time this method is called it should be true.

The position of the selected album in the list will be passed in and can be used with the Cursor object to get at the data about which album it was by calling the moveToPosition method.

if (cursor.moveToPosition(position)) {

Assuming the moveToPosition was successful, we are going to start all over again querying the MediaStore. This time, though, we are going to run our managedOuery on MediaStore.Audio.Media.EXTERNAL_CONTENT_URI as we want access to the individual media files.

First we choose the columns that we want returned.

MediaStore.Audio.Media.DATA,

MediaStore.Audio.Media._ID,

MediaStore.Audio.Media.TITLE,

MediaStore.Audio.Media.DISPLAY_NAME,

MediaStore.Audio.Media.MIME_TYPE,

Next we need to construct an SQL WHERE clause for our query. Since we want only media files that belong to a specific album, our WHERE clause should indicate that.

In normal SQL, the WHERE clause would look like this:

WHERE album = 'album name'

Since we are working with a managedOuery, we don't need the word WHERE and we don't need to pass in what it should be equal to. Instead we substitute in a '?'. Therefore for the foregoing version, the String would be as follows:

Since we don't know the actual name of the column as we are working with a constant. We'll use that to construct the WHERE clause.

String where = android.provider.MediaStore.Audio.Media.ALBUM + "=?";

Finishing off the WHERE clause, we need the data that will be substituted in for the ?s in the WHERE. This will be an array of Strings, one for each of the ?s used. In our case, we want to use the name of the album that was selected. Since we have the Cursor in the right position, we simply need to call the Cursor's getString method on the right column, which we get by calling the Cursor's getColumnIndex method on the column name.

String whereVal[] = ^ {cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM))};

Last we can specify that we want the results to be ordered by a specific column's value. For this let's create a String variable that will contain the name of the column that we want the results ordered by.

String orderBy = android.provider.MediaStore.Audio.Media.TITLE;

Finally, we can run our managedOuery method, passing in the Uri, the columns, the WHERE clause variable, the WHERE clause data, and the ORDER BY variable.

cursor = managedOuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,^ columns, where, whereVal, orderBy);

Again, we'll use the ListActivity methods to manage the Cursor object and present the results in a list.

String[] displayFields = new String[]^ {MediaStore.Audio.Media.DISPLAY_NAME};

int[] displayViews = new int[] {android.R.id.textl}; setListAdapter(new SimpleCursorAdapter(this,^

android.R.layout.simple_list_item_1, cursor, displayFields,^

displayViews));

The last thing we'll do is change the currentState variable to be STATE_SELECT_SONG so that the next time through this method, we skip all of this as the user will be selecting a song and not an album.

currentState = STATE_SELECT_SONG;

} else if (currentState == STATE_SELECT_SONG) {

When the user selects a song from the list after selecting an album, he or she will enter this part of the method as currentState will equal STATE_SELECT_SONG.

if (cursor.moveToPosition(position)) {

Using the same moveToPosition call on the Cursor object as we did previously, we can get at the song that was actually selected. In this case, we are getting at the column that contains the path to the file and the MIME-type of that file. We are converting it to a File and creating an intent to start the built-in music player application.

int fileColumn = cursor.getColumnIndex (MediaStore.Audio.Media.DATA); int mimeTypeColumn = cursor.getColumnIndex^ (MediaStore.Audio.Media.MIME_TYPE);

String audioFilePath = cursor.getString(fileColumn); String mimeType = cursor.getString(mimeTypeColumn);

Intent intent = new Intent(android.content.Intent.ACTION_VIEW);

File newFile = new File(audioFilePath); intent.setDataAndType(Uri.fromFile(newFile), mimeType);

startActivity(intent);

Here is the layout XML file that is being used by the foregoing code. You'll notice that it contains a ListView with the ID list. This is the default ID that needs to be used with the ListActivity that we are extending.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent"

android:layout_height="fill_parent" >

<ListView android:id="@+android:id/list" android:layout_width="wrap_content"^ android:layout_height="wrap_content"></ListView> </LinearLayout>

That wraps up our sample application, which allows us to browse and select songs to play by album using the MediaStore. Using very similar methods, we could build it out so that we could browse and select music based upon artist and genre as well.

+1 0

Post a comment