android media player

22
Android Media Player People ask me all the time how to develop an Android program that can load up and play music. Sadly, there are not a lot of good answers on the internet. The good news is, it's really not all that bad. Today we are going to: 1. Learn how to implement features of the android.media.MediaPlayer class. 2. Load Drawables on the fly from the SD card using the createFromPath() function 3. Learn what assets are and how to incorporate these into our program 4. Learn how to load media from an SD card 5. Write a fully functional Media Player program 6. Become a better Java Monkey! By the end of this tutorial, you will not only have a fully functional simple media player, but you will also have a clear understanding of how to incorporate media into your apps. Before going any further, make sure your development environment is set up correctly for Android development. If you are unsure, check my guide here. *** I recommend you download the source code for this project here, as it contains sample tracks and all of the drawables you will need, as well as a cheesy icon I made myself *** File New Android Project New Android Project (Name, Path, Target)

Upload: ajaypal-yadav

Post on 29-Oct-2015

72 views

Category:

Documents


1 download

DESCRIPTION

android apps

TRANSCRIPT

Page 1: Android Media Player

Android Media Player

People ask me all the time how to develop an Android program that can load up and play music.

Sadly, there are not a lot of good answers on the internet. The good news is, it's really not all that

bad. Today we are going to:

1. Learn how to implement features of the android.media.MediaPlayer class.

2. Load Drawables on the fly from the SD card using the createFromPath() function

3. Learn what assets are and how to incorporate these into our program

4. Learn how to load media from an SD card

5. Write a fully functional Media Player program

6. Become a better Java Monkey!

By the end of this tutorial, you will not only have a fully functional simple media player, but you will

also have a clear understanding of how to incorporate media into your apps. Before going any

further, make sure your development environment is set up correctly for Android development. If you

are unsure, check my guide here.

*** I recommend you download the source code for this project here, as it contains sample tracks

and all of the drawables you will need, as well as a cheesy icon I made myself ***

File New Android Project

New Android Project (Name, Path, Target)

Page 2: Android Media Player

New Android Project (Properties)

File Import

Import Existing Projects into Workspace

Browse for the project you want to import and click OK, check the checkbox, and then click Finish

Here we go!

When making a media player, a few things come to mind:

1. There will be multiple tracks to load

2. Moving from track to track

3. Play, Pause, and Stop functionality

4. Shuffle and Loop functionality

5. The SD Card must be mounted by the phone in order to load music/pictures from it

Doesn't sound too hard right? So let's begin:

1. Create a new project File > New > Android Project

Page 3: Android Media Player

2. Name it MyMediaPlayer

3. Set the MinSdk to 3 and the TargetSdk to 8

4. Name your package

5. Eclipse will create the onCreate Activity for you (e.g. 'MyMediaPlayerActivity.java' ) If you want

to name it something else, go ahead; it won't hurt anything.

If you have downloaded the source for this project and want to simply import it:

1. Make sure that theMyMediaPlayer project is in the "Eclipse Projects" folder

2. File > Import > Existing Projects into Workspace

3. Browse > MyMediaPlayer > OK

4. Make sure the checkbox in the "Projects:" box is checked > Finish

Now let's take a look at the manifest file.

Manifest.xml

?

12345678910111213141516171819

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"      package="com.technegames.mymediaplayer"      android:versionCode="1"      android:versionName="1.0">    <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8" />     <application android:icon="@drawable/icon" android:label="@string/app_name">        <activity android:name=".MyMediaPlayerActivity" android:configChanges="orientation|keyboardHidden"                  android:label="@string/app_name">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>

     </application>    <uses-permission android:name="android.permission.WAKE_LOCK" /></manifest>

Manifest

As you can see, the manifest acts like a parental guardian for your App. It is responsible for

supplying the versionCode, which is important when uploading applications to the Android Market. It

also determines how and when activities can be launched via intent filters. The manifest is also

Page 4: Android Media Player

where you specify certain permissions such as internet access. For example, in MyMediaPlayer, we

use the WAKE_LOCK permission so that we can keep the phone on while the app is running.

Otherwise, the song would pause itself after 20 seconds or so. Without the permission specified in

the manifest, the application would crash upon loading because it attempted to utilize a wake lock

without permission.

The Android Manifest is an important XML document, so familiarize yourself with it. Eclipse will

generate a manifest file for you when creating a new project, so if you created this project from

scratch, the only line you would have to add would be the "uses-permission" for the WAKE_LOCK

Alright, while on the topic of XML documents, let's take a look at our main layout. After this we will

get to the Java code I promise!

main.xml

?

12345678910111213141516171819202122232425262728

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/screen" android:layout_width="fill_parent" android:layout_height="fill_parent"    <LinearLayout android:orientation="vertical" android:layout_alignParentTop="true"        android:layout_alignParentLeft="true" android:layout_width="fill_parent" android:layout_height="fill_parent"        android:weightSum="7" >        <LinearLayout android:layout_weight="6" android:orientation="vertical" android:layout_alignParentTop="true"            android:layout_alignParentLeft="true" android:layout_width="fill_parent" android:layout_height="0dip"            <ImageView android:id="@+id/bg" android:layout_width="fill_parent" android:layout_height="fill_parent"            </ImageView>        </LinearLayout>        <LinearLayout android:layout_weight="1" android:id="@+id/buttons" android:orientation="horizontal"            android:layout_alignParentBottom="true" android:layout_alignParentLeft="true"            android:layout_width="fill_parent" android:layout_height="0dip" android:background="#FFFFFF"            <Button android:id="@+id/btnPrevious" android:layout_width="0dip" android:layout_height="fill_parent"                android:layout_weight="1" android:background="@drawable/previous" android:layout_margin="5dp"                android:onClick="click" />            <View android:layout_weight="1" android:layout_width="0dip" android:layout_height="0dip"            <Button android:id="@+id/btnPlay" android:layout_width="0dip" android:layout_height="fill_parent"                android:layout_weight="1" android:background="@drawable/play" android:layout_margin="5dp"                android:onClick="click" />            <View android:layout_weight="1" android:layout_width="0dip" android:layout_height="0dip"            <Button android:id="@+id/btnNext" android:layout_width="0dip" android:layout_height="fill_parent"                android:layout_weight="1" android:background="@drawable/next" android:layout_margin="5dp"                android:onClick="click" />        </LinearLayout>    </LinearLayout></RelativeLayout>

main

Page 5: Android Media Player

If you are unfamilar with XML, at first glance this code might look very confusing. I assure you it is

very simple, and is one of the greatest features of Android. If you are coming into Android

Development from a Java Swing background, you will be happy to know that you can completely

separate your layout/gui elements from your main code by setting it up in an XMLdocument.

In the MyMediaPlayer program, we use a Relative Layout with Linear Layouts nested inside. The

Relative Layout allows us to specify where the Linear Layouts are placed in relation to each other.

The topmost Linear Layout is used for the album art. We use

theandroid:layout_alignParentTop="true" and android:layout_alignParentLeft="true"to specify that

the album art layout is aligned to the topleft corner of the screen. We use layout_weight to dictate

that the layout containing the image takes up 6/7 of the screen, with the remaining 1/7 for the

buttons. Speaking of buttons, in each of the buttons there is android:onClick="click". This means that

when you click on any of these buttons, they call a function called click in

MyMediaPlayerActivity.java, which we will get to in a bit.

The best way to learn Android layouts is to simply play around with one that works. Adjust settings

and values and notice the changes. Parent/Child relationships can get very complicated, so it is best

to just take it one step at a time. There is a nice Tool online that generates an XML layout based on

what you drag-and-drop onto the screen. If you think this tool may help you with Android Layouts,

click here to download it!

Alright, Let's dive into some java code!

Music.java

?

12345678910111213141516171819

package com.technegames.mymediaplayer; import java.io.FileDescriptor;import java.io.IOException; import android.content.res.AssetFileDescriptor;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener; public class Music implements OnCompletionListener{    MediaPlayer mediaPlayer;    boolean isPrepared = false;         public Music(AssetFileDescriptor assetDescriptor){        mediaPlayer = new MediaPlayer();        try{            mediaPlayer.setDataSource(assetDescriptor.getFileDescriptor(), assetDescriptor.getStartOffset(), assetDescriptor.getLength());            mediaPlayer.prepare();            isPrepared = true;            mediaPlayer.setOnCompletionListener(this);        } catch(Exception ex){            throw new RuntimeException("Couldn't load music, uh oh!");

Page 6: Android Media Player

20212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465

        }    }

         public Music(FileDescriptor fileDescriptor){        mediaPlayer = new MediaPlayer();        try{            mediaPlayer.setDataSource(fileDescriptor);            mediaPlayer.prepare();            isPrepared = true;            mediaPlayer.setOnCompletionListener(this);        } catch(Exception ex){            throw new RuntimeException("Couldn't load music, uh oh!");        }    }

         public void onCompletion(MediaPlayer mediaPlayer) {        synchronized(this){            isPrepared = false;        }    }

     public void play() {        if(mediaPlayer.isPlaying()){            return;        }        try{            synchronized(this){                if(!isPrepared){                    mediaPlayer.prepare();                }                mediaPlayer.start();            }        } catch(IllegalStateException ex){            ex.printStackTrace();        } catch(IOException ex){            ex.printStackTrace();        }    }

     public void stop() {        mediaPlayer.stop();        synchronized(this){            isPrepared = false;        }    }

         public void switchTracks(){        mediaPlayer.seekTo(0);        mediaPlayer.pause();    }

         public void pause() {        mediaPlayer.pause();    }

 

Page 7: Android Media Player

66676869707172737475767778798081828384858687888990919293949596979899100

    public boolean isPlaying() {        return mediaPlayer.isPlaying();    }

         public boolean isLooping() {        return mediaPlayer.isLooping();    }

         public void setLooping(boolean isLooping) {        mediaPlayer.setLooping(isLooping);    }

     public void setVolume(float volumeLeft, float volumeRight) {        mediaPlayer.setVolume(volumeLeft, volumeRight);    }

     public void dispose() {        if(mediaPlayer.isPlaying()){            stop();        }        mediaPlayer.release();    }}

Music

Alright, if you gave the above code a good scan, you probably noticed that Music.java is responsible

for instantiating our media player and controlling it. It implements the OnCompletionListener so that

we can monitor when a song is finished playing. The reason we do all of this in a separate class is

because we will instantiate it every time we seek to a different track, rather than trying to load all of

the tracks into memory.

Whenever you feel comfortable with the Music class, let's move on to the main attraction,

MyMediaPlayerActivity.java

MyMediaPlayerActivity.java Variables

Page 8: Android Media Player

?

123456789101112131415161718192021222324252627282930313233343536373839404142434445

package com.technegames.mymediaplayer; import java.io.File;import java.io.FileDescriptor;import java.io.FileInputStream;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.Random; import android.app.Activity;import android.content.Context;import android.content.res.AssetFileDescriptor;import android.content.res.AssetManager;import android.graphics.drawable.Drawable;import android.media.AudioManager;import android.os.Bundle;import android.os.Environment;import android.os.PowerManager;import android.os.PowerManager.WakeLock;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.Window;import android.view.WindowManager;import android.widget.Button;import android.widget.ImageView;import android.widget.Toast; public class MyMediaPlayerActivity extends Activity {    WakeLock wakeLock;    private static final String[] EXTENSIONS = { ".mp3", ".mid", ".wav", ".ogg", ".mp4"    List<String> trackNames; //Playable Track Titles    List<String> trackArtworks; //Track artwork names    AssetManager assets; //Assets (Compiled with APK)    File path; //directory where music is loaded from on SD Card    File path2; //directory where album artwork is loaded from on SD Card    Music track; //currently loaded track    ImageView bg; //Track artwork    Button btnPlay; //The play button will need to change from 'play' to 'pause', so we need an instance of it    Random random; //used for shuffle    boolean shuffle; //is shuffle mode on?    boolean isTuning; //is user currently jammin out, if so automatically start playing the next track    int currentTrack; //index of current track selected    int type; //0 for loading from assets, 1 for loading from SD card

Page 9: Android Media Player

MyMediaPlayerActivity Variables

Before we discuss the onCreate activity, let's talk about our Class Level variables.

First, we have our wakeLock, which if you recall from earlier is used to keep the phone on. We also

have our EXTENSIONS array, which is used to validate that the files we load into our program are

actual sound files. The trackNames ArrayList is used to store all of the track names in memory for

reference by the media player. The trackArtworks ArrayList matches the trackNames List except it

does not contain any extensions. It is used when trying to find a picture with the same name as the

track currently playing and if so load that image. The assets are used to retrieve a list of all the files

in the 'assets' folder of your program. Assets are the resources that get compiled along with your

program. I've included 4 tracks in the source of this program below. The program by default loads up

the assets folder. By pressing the MENU button on your phone and then clicking the SOURCE

option you can specify the program to load tracks from the 'music' folder on the root of your SD card.

The rest of the variables are pretty self explanatory and if not I've included inline comments.

MyMediaPlayerActivity.java onCreate, onResume, onPause

?

123456789101112131415161718192021222324252627

@Overridepublic void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    requestWindowFeature(Window.FEATURE_NO_TITLE);    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);    setVolumeControlStream(AudioManager.STREAM_MUSIC);    PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);    wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "MyMediaPlayer");    setContentView(R.layout.main);

         initialize(0);}

 @Overridepublic void onResume(){    super.onResume();    wakeLock.acquire();}

 @Overridepublic void onPause(){    super.onPause();    wakeLock.release();    if(track != null){        if(track.isPlaying()){            track.pause();            isTuning = false;            btnPlay.setBackgroundResource(R.drawable.play);        }        if(isFinishing()){            track.dispose();            finish();

Page 10: Android Media Player

282930313233343536373839

        }    } else{        if(isFinishing()){            finish();        }    }}

onCreate, onResume, onPause

These functions override their parent counterparts from Activity class. They are important because

they handle the Activity Lifecycle. Lines 4-8 set up full-screen mode and a wakeLock to insure that

the phone screen does not turn off (which would result in an onPause event). On Line 9 we set the

content view to the layout we created above, meaning we will have an ImageView and 3 Buttons on

the screen. The last thing we do in onCreate is call initialize(0). The 0 in the parentheses means that

the media player will load files from the program's assets upon load. Change it to a 1 to load from

the SD Card upon load. We will look at the initialize method in the next code block.

The onResume method is where we will acquire the wakeLock. We do this in onResume because

we release it in the onPause method. If we were to acquire the wakeLock in the onCreate method, it

would only be done so once.

The onPause method is fired when the program is interrupted. For example, the phone is receiving a

phone call or the user presses the HOME button. To prepare for something like this, we override the

onPause method from Activity. If track is not null and it is playing it gets paused and the pause

button gets turned into a play button. We could have also chosen to override onStop, but the

isFinishing method serves the same purpose. If the program is finishing, we dispose the mediaplayer

object and call the Activity's finish() method.

MyMediaPlayerActivity.java initialize, addTracks, loadTrack

?

123456789

private void initialize(int type){    bg = (ImageView) findViewById(R.id.bg);    btnPlay = (Button) findViewById(R.id.btnPlay);    btnPlay.setBackgroundResource(R.drawable.play);    trackNames = new ArrayList<String>();    trackArtworks = new ArrayList<String>();    assets = getAssets();    currentTrack = 0;    shuffle = false;    isTuning = false;

Page 11: Android Media Player

10111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

    random = new Random();    this.type = type;

         addTracks(getTracks());    loadTrack();}

 //Generate a String Array that represents all of the files foundprivate String[] getTracks(){    if(type == 0){        try {            String[] temp = getAssets().list("");            return temp;        } catch (IOException e) {            e.printStackTrace();            Toast.makeText(getBaseContext(), e.getMessage(), Toast.LENGTH_LONG).show();        }    } else if(type == 1){        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)                 || Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY)){            path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);            path2 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);            String[] temp = path.list();            return temp;        } else{            Toast.makeText(getBaseContext(), "SD Card is either mounted elsewhere or is unusable", Toast.LENGTH_LONG).show();        }    }    return null;}

 //Adds the playable files to the trackNames Listprivate void addTracks(String[] temp){    if(temp != null){        for(int i = 0; i < temp.length; i++){            //Only accept files that have one of the extensions in the EXTENSIONS array            if(trackChecker(temp[i])){                trackNames.add(temp[i]);                trackArtworks.add(temp[i].substring(0, temp[i].length()-4));            }        }        Toast.makeText(getBaseContext(), "Loaded " + Integer.toString(trackNames.size()) + " Tracks", Toast.LENGTH_SHORT).show();    }}

 //Checks to make sure that the track to be loaded has a correct extensonprivate boolean trackChecker(String trackToTest){    for(int j = 0; j < EXTENSIONS.length; j++){        if(trackToTest.contains(EXTENSIONS[j])){            return true;        }    }    return false;}

 

Page 12: Android Media Player

5657585960616263646566676869707172737475

//Loads the track by calling loadMusicprivate void loadTrack(){    if(track != null){        track.dispose();    }    if(trackNames.size() > 0){        track = loadMusic(type);        setImage("drawable/" + trackArtworks.get(currentTrack));    }}

initialize, addTracks, loadTrack

The initialize method initializes all of our variables so that we do not end up getting null pointer

exceptions. The bottom of the method adds all of the tracks from either the compiled assets or from

"scard/music", making sure to only add tracks with a valid extension ( e.g. ".mp3", ".mid" ) After that,

the loadTrack() method is called.

The loadTrack() method will be called everytime a new track has been selected. In the loadTrack()

method, we call loadMusic() and setImage(), which we will take a look at below.

MyMediaPlayerActivity.java loadMusic, setImage

?

12345678910111213

//loads a Music instance using either a built in asset or an external resourceprivate Music loadMusic(int type){    switch(type){    case 0:        try{            AssetFileDescriptor assetDescriptor = assets.openFd(trackNames.get(currentTrack));            return new Music(assetDescriptor);        } catch(IOException e){            e.printStackTrace();            Toast.makeText(getBaseContext(), "Error Loading " + trackNames.get(currentTrack), Toast.LENGTH_LONG).show();        }        return null;    case 1:        try{            FileInputStream fis = new FileInputStream(new File(path, trackNames.get(currentTrack)));            FileDescriptor fileDescriptor = fis.getFD();

Page 13: Android Media Player

14151617181920212223242526272829303132333435363738394041424344454647484950515253

            return new Music(fileDescriptor);        } catch(IOException e){            e.printStackTrace();            Toast.makeText(getBaseContext(), "Error Loading " + trackNames.get(currentTrack), Toast.LENGTH_LONG).show();        }        return null;    default:        return null;    }}

 //Sets the background image to match the track currently playing or a default imageprivate void setImage(String name) {    if(type == 0){        int imageResource = getResources().getIdentifier(name, null, getPackageName());        if(imageResource != 0){            Drawable image = getResources().getDrawable(imageResource);            bg.setImageDrawable(image);        } else{            int defaultImageResource = getResources().getIdentifier("drawable/defaultbg", null, getPackageName());            if(defaultImageResource != 0){                Drawable image = getResources().getDrawable(defaultImageResource);                bg.setImageDrawable(image);            }        }    } else if(type == 1){        if(new File(path2.getAbsolutePath(), trackArtworks.get(currentTrack) + ".jpg").exists()){            bg.setImageDrawable(Drawable.createFromPath(path2.getAbsolutePath() + "/"         } else{            int defaultImageResource = getResources().getIdentifier("drawable/defaultbg", null, getPackageName());            if(defaultImageResource != 0){                Drawable image = getResources().getDrawable(defaultImageResource);                bg.setImageDrawable(image);            }        }    }}

loadMusic, setImage

The loadMusic is probably the most important method in the entire program. You will want to learn

the Music.java class and this method because they can translate to any program that needs music,

not just a media player.

Page 14: Android Media Player

In our loadMusic() method, we either load up a track from our compiled assets (the ones I include

with the download above) or one of your songs located in the "music" folder on your SD Card.

The setImage() method is called immediately the loadMusic() method to change the album art

accordingly. In our simple example, it simply scans the "pictures" folder on your SD Card for a

picture with same name as the track currently playing excluding the extension and sets it

accordingly. If no image can be found, a default image is loaded up from the drawable folder of your

project.

Alright, I know we have covered a lot of ground here, but we are almost done. The next two sections

cover the user input.

MyMediaPlayerActivity.java Menu, Options, setShuffle

?

12345678910111213141516171819202122232425262728293031

@Overridepublic boolean onCreateOptionsMenu(Menu menu){    super.onCreateOptionsMenu(menu);    createMenu(menu);    return true;}

 private void createMenu(Menu menu){    MenuItem miLooping = menu.add(0, 0, 0, "Looping");{        miLooping.setIcon(R.drawable.looping);    }    MenuItem miShuffle = menu.add(0, 1, 1, "Shuffle");{        miShuffle.setIcon(R.drawable.shuffle);    }    MenuItem miStop = menu.add(0, 2, 2, "Stop");{        miStop.setIcon(R.drawable.stop);    }    MenuItem miSource = menu.add(0, 3, 3, "Source");{        miSource.setIcon(R.drawable.source);    }}

 @Overridepublic boolean onOptionsItemSelected(MenuItem item){    switch(item.getItemId()){    case 0:        //Set Looping        synchronized(this){            if(track.isLooping()){                track.setLooping(false);                Toast.makeText(getBaseContext(), "Playing Tracks Sequentially", Toast.LENGTH_SHORT).show();            } else{                track.setLooping(true);                Toast.makeText(getBaseContext(), "Looping " + trackNames.get(currentTrack), Toast.LENGTH_SHORT).show();            }        }        return true;

Page 15: Android Media Player

32333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677

    case 1:        //Set Shuffle        synchronized(this){            if(shuffle){                setShuffle(false);            } else{                setShuffle(true);            }        }        return true;    case 2:        //Stop Music        synchronized(this){            track.switchTracks();            btnPlay.setBackgroundResource(R.drawable.play);        }        return true;    case 3:        //Change Source from Assets to SD Card and vice versa        synchronized(this){            type++;            if(type > 1){                type = 0;            }        }        if(type == 0){            Toast.makeText(getBaseContext(), "Loading Tracks from Assets ", Toast.LENGTH_SHORT).show();        } else if(type == 1){            Toast.makeText(getBaseContext(), "Loading Tracks from SD Card", Toast.LENGTH_SHORT).show();        }        initialize(type);        return true;    default:        return false;    }}

 //Simply sets shuffle to isShuffle and then displays a message for confirmationprivate void setShuffle(boolean isShuffle) {    shuffle = isShuffle;    if(shuffle){        Toast.makeText(getBaseContext(), "Shuffle On", Toast.LENGTH_SHORT).show();    } else{        Toast.makeText(getBaseContext(), "Shuffle Off", Toast.LENGTH_SHORT).show();    }}

Page 16: Android Media Player

787980818283Menu, Options, setShuffle

First off, we must override a functon called onCreateOptionsMenu(). It is called whenever the Menu

Button is pressed on your phone. It is particularly useful if there are extra controls you want to

provide to your users without having to clutter the screen with additional buttons. In our

onCreateOptionsMenu() method, we call a createMenu() method.

The createMenu() method is responsible for setting populating the menu options. We have 4 menu

options in total: "Looping", "Shuffle", "Stop", and "Source"

The onOptionsItemSelected() method provides functionality for these menu options. We use a

switch on the item.getItemId() function, which returns an int that distinguishes the options from each

other. The "Looping" and "Stop" Options seem pretty self explanatory, so I won't go over those.

When the "Shuffle" Option is clicked, the setShuffle() method is called, which sets shuffle to to either

true of false and displays a message for confirmation.

When the "Source" Option is clicked, type is switched from 0 to 1 and vice versa and the initialize()

method is called again, except this time with the new type. If the type is set to 1, the SD Card will be

loaded up instead of the "assets" folder of your project.

Alright, let's move on to the on-screen controls!

MyMediaPlayerActivity.java click, setTrack, playTrack

?

123456789101112131415

public void click(View view){    int id = view.getId();    switch(id){    case R.id.btnPlay:        synchronized(this){            if(isTuning){                isTuning = false;                btnPlay.setBackgroundResource(R.drawable.play);                track.pause();            } else{                isTuning = true;                btnPlay.setBackgroundResource(R.drawable.pause);                playTrack();            }        }        return;    case R.id.btnPrevious:        setTrack(0);

Page 17: Android Media Player

16171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061

        loadTrack();        playTrack();        return;    case R.id.btnNext:        setTrack(1);        loadTrack();        playTrack();        return;    default:        return;    }}

 private void setTrack(int direction){    if(direction == 0){        currentTrack--;        if(currentTrack < 0){            currentTrack = trackNames.size()-1;        }    } else if(direction == 1){        currentTrack++;        if(currentTrack > trackNames.size()-1){            currentTrack = 0;        }    }    if(shuffle){        int temp = random.nextInt(trackNames.size());        while(true){            if(temp != currentTrack){                currentTrack = temp;                break;            }            temp++;            if(temp > trackNames.size()-1){                temp = 0;            }        }    }}

 //Plays the Trackprivate void playTrack(){    if(isTuning && track != null){        track.play();        Toast.makeText(getBaseContext(), "Playing " + trackNames.get(currentTrack).substring(0, trackNames.get(currentTrack).length()-4), Toast.LENGTH_SHORT).show();    }}

Page 18: Android Media Player

62636465click, setTrack, playTrack, setShuffle

If you recall from earlier when we created our main.xml layout, we talked about the

android:onClick="click" in each of the buttons. The click function must be public, have a return type

of void, and accept a View instance as a parameter; otherwise you will receive errors. Since all of

the buttons call the same function, how do we know which button called it? We set up a switch on

the view.getId() function, which returns the id of the button. The Next and Previous Buttons simply

call the setTrack() method, the loadTrack() method we discussed earlier, and then the playTrack()

method, which plays the newly loaded song if the user was playing the last song.

The setTrack() method moves the currentTrack index either forward or backward. If shuffle is on,

then currentTrack index becomes a random number not equal to what it was before the method call.

The playTrack() method simply calls the play() method from Music.java, provided that track is not

null.

Run Run As Android Application

Compiling and Running!

Did I forget anything? I think that's about it, if you have been following along and creating your

project from scratch, make sure you do not have any pesky red underlines in your code. At this

point, we can go ahead and run our program. You can either click Run > Run As > Android

Application or right-click your project and Run As > Android Application

Well? Do the Buttons work? How about the Menu Options? Try alternating between Loop and

Shuffle Mode. Click the Source button to load up your SD Card, but make sure you disconnect your

phone from the PC first!

Page 19: Android Media Player

Playing the built in tracks from the "assets" folder of your project

Playing Songs from the SD Card's "music" folder

Congratulations

You now have a working custom media player for your Android Device! The program works

decently, but there is more to be desired isn't there? If you wanted to publish this it most likely would

not perform well on the Market, as there are much better media players available. To make this

media player better, you could add a thread that constantly checks if the onCompletionListener

event is satisfied and if so go to the next song. Or you could stream album art from a locally stored

database instead of relying on the "pictures" folder of the SD card. Animating visualizations would be

nice too wouldn't they? The possibilities are endless! As an Android Developer, these choices are

entirely yours, so experiment and try new things!

*** If you had any problems with this tutorial, get the source code hereand take a look at it. Play

around with the code and understand how it all works together. Good Luck! ***