In this tutorial i am going to discuss building a simple audio player with basic controls like play, pause, forward, backward, next, previous, playlist and seekbar. This app basically will read all audio files(.mp3) from sdcard and plays selected song. For this tutorial i am referencing MediaPlayer and go through it if you need any documentation about usage.
Android MediaPlayer Class
Android SDK is providing MediaPlayer Class to access android in built mediaplayer services like playing audio, video etc., In this tutorial i am using following functions of this class to control audio player.
MediaPlayer mp = new MediaPlayer(); // Set data source - setDataSource("/sdcard/path_to_song"); // Play audio mp.start(); // Pause audio mp.pause(); // Reset mediaplayer mp.reset(); // Get song length duration - in milliseconds mp.getDuration(); // Get current duration - in milliseconds mp.getCurrentDuration(); // Move song to particular second - used for Forward or Backward mp.seekTo(positon); // position in milliseconds // Check if song is playing or not mp.isPlaying(); // returns true or false
1. Designing the Audio Player Layout
Design your audio player using some graphic designing softwares like photoshop. I used photoshop to design this app layout. If you are not aware of designing just download the required images from the internet. Following is a screenshot of the audio player which we are going to build in this tutorial. (You can find this layout PSD in the download code)
2. Preparing Required Icons and Images
Once you are done with your app layout design, prepare the required icons and background images for the audio player application. Prepare your icons in different states like default, focused and pressed and place them all in your drawable folder.
3. Writing XML layouts for ICON states (default/hover/pressed)
After saving all the icons with different states, we need to write xml drawable for each icon. Following is a sample for play button. Save this file under drawable folder.
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/img_btn_play_pressed" android:state_focused="true" android:state_pressed="true" /> <item android:drawable="@drawable/img_btn_play_pressed" android:state_focused="false" android:state_pressed="true" /> <item android:drawable="@drawable/img_btn_play_pressed" android:state_focused="true" /> <item android:drawable="@drawable/img_btn_play" android:state_focused="false" android:state_pressed="false" /> </selector>
Note: You need to write xml drawable for each icon you used for the player (like btn_pause.xml, btn_next.xml etc,.)
4. Writing XML design for SeekBar
In this tutorial i used customized SeekBar to show song progress. You can design the style of default SeekBar using xml styles. In your drawable folder create to xml files and type the following code.
Changing SeekBar background:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <clip> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:src="@drawable/img_seekbar_progress_blue" android:tileMode="repeat" android:antialias="true" android:dither="false" android:filter="false" android:gravity="left" /> </clip> </item> </layer-list>
Changing SeekBar Progress:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@android:id/background" android:drawable="@drawable/img_seekbar_bg" android:dither="true"> </item> <item android:id="@android:id/secondaryProgress"> <clip> <shape> <gradient android:startColor="#80028ac8" android:centerColor="#80127fb1" android:centerY="0.75" android:endColor="#a004638f" android:angle="270" /> </shape> </clip> </item> <item android:id="@android:id/progress" android:drawable="@drawable/seekbar_progress_bg" /> </layer-list>
Actual seekbar which uses above xml files:
<SeekBar android:id="@+id/songProgressBar" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginRight="20dp" android:layout_marginLeft="20dp" android:layout_marginBottom="20dp" android:layout_above="@id/player_footer_bg" android:thumb="@drawable/seek_handler" android:progressDrawable="@drawable/seekbar_progress" android:paddingLeft="6dp" android:paddingRight="6dp"/>
5. Writing XML for Player Layout
So far we created separate xml layout for all the icons, seekbar. Now we need to combine everything into single layout. Create a new file called player.xml under layout folder and paste the following code.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/player_background"> <!-- Player Header --> <LinearLayout android:id="@+id/player_header_bg" android:layout_width="fill_parent" android:layout_height="60dip" android:background="@layout/bg_player_header" android:layout_alignParentTop="true" android:paddingLeft="5dp" android:paddingRight="5dp"> <!-- Song Title --> <TextView android:id="@+id/songTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:textColor="#04b3d2" android:textSize="16dp" android:paddingLeft="10dp" android:textStyle="bold" android:text="The Good, The Bad And The Ugly" android:layout_marginTop="10dp"/> <!-- Playlist button --> <ImageButton android:id="@+id/btnPlaylist" android:layout_width="wrap_content" android:layout_height="fill_parent" android:src="@drawable/btn_playlist" android:background="@null"/> </LinearLayout> <!-- Song Thumbnail Image --> <LinearLayout android:id="@+id/songThumbnail" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingTop="10dp" android:paddingBottom="10dp" android:gravity="center" android:layout_below="@id/player_header_bg"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/adele"/> </LinearLayout> <!-- Player Footer --> <LinearLayout android:id="@+id/player_footer_bg" android:layout_width="fill_parent" android:layout_height="100dp" android:layout_alignParentBottom="true" android:background="@layout/bg_player_footer" android:gravity="center"> <!-- Player Buttons --> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" android:background="@layout/rounded_corner" android:paddingLeft="10dp" android:paddingRight="10dp"> <!-- Previous Button --> <ImageButton android:id="@+id/btnPrevious" android:src="@drawable/btn_previous" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null"/> <!-- Backward Button --> <ImageButton android:id="@+id/btnBackward" android:src="@drawable/btn_backward" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null"/> <!-- Play Button --> <ImageButton android:id="@+id/btnPlay" android:src="@drawable/btn_play" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null"/> <!-- Forward Button --> <ImageButton android:id="@+id/btnForward" android:src="@drawable/btn_forward" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null"/> <!-- Next Button --> <ImageButton android:id="@+id/btnNext" android:src="@drawable/btn_next" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null"/> </LinearLayout> </LinearLayout> <!-- Progress Bar/Seek bar --> <SeekBar android:id="@+id/songProgressBar" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginRight="20dp" android:layout_marginLeft="20dp" android:layout_marginBottom="20dp" android:layout_above="@id/player_footer_bg" android:thumb="@drawable/seek_handler" android:progressDrawable="@drawable/seekbar_progress" android:paddingLeft="6dp" android:paddingRight="6dp"/> <!-- Timer Display --> <LinearLayout android:id="@+id/timerDisplay" android:layout_above="@id/songProgressBar" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginRight="20dp" android:layout_marginLeft="20dp" android:layout_marginBottom="10dp"> <!-- Current Duration Label --> <TextView android:id="@+id/songCurrentDurationLabel" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="left" android:textColor="#eeeeee" android:textStyle="bold"/> <!-- Total Duration Label --> <TextView android:id="@+id/songTotalDurationLabel" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="right" android:textColor="#04cbde" android:textStyle="bold"/> </LinearLayout> <!-- Repeat / Shuffle buttons --> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_above="@id/timerDisplay" android:gravity="center"> <!-- Repeat Button --> <ImageButton android:id="@+id/btnRepeat" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/btn_repeat" android:layout_marginRight="5dp" android:background="@null"/> <!-- Shuffle Button --> <ImageButton android:id="@+id/btnShuffle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/btn_shuffle" android:layout_marginLeft="5dp" android:background="@null"/> </LinearLayout> </RelativeLayout>
The above xml will give following output layout.
6. Writing XML for PlayList ListView
Playlist is displayed using a listview. If you are not aware of listview go through this Android ListView Tutorial and get an idea of listview layout.
⇒ Create an xml file under drawable folder and name it as list_selector.xml and type following code. This xml is used for gradient background for list item.
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Selector style for listrow --> <item android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/gradient_bg" /> <item android:state_pressed="true" android:drawable="@drawable/gradient_bg_hover" /> <item android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/gradient_bg_hover" /> </selector>
⇒ Create a new xml file under layout layout folder and name it as playlist.xml and type the following code. This xml file is for listview.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:divider="#242424" android:dividerHeight="1dp" android:listSelector="@drawable/list_selector" /> </LinearLayout>
⇒ Also create a new xml file under layout folder for single List Item. Name file as playlist_item.xml and type following code. This xml file is for single list item which holds song title.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" android:background="@drawable/list_selector" android:padding="5dp"> <TextView android:id="@+id/songTitle" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="16dp" android:padding="10dp" android:color="#f3f3f3"/> </LinearLayout>
By using above layout we can achieve following list view by loading data into it.
7. Writing Class for reading MP3 files from SDcard
So far we are done with static layouts for the player. Now the actual code starts.
Create a new class file and name it as SongsManager.java. This class will read all the files from device sdcard and filters the files which are having .mp3 extension.
package com.androidhive.musicplayer; import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; import java.util.HashMap; public class SongsManager { // SDCard Path final String MEDIA_PATH = new String("/sdcard/"); private ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>(); // Constructor public SongsManager(){ } /** * Function to read all mp3 files from sdcard * and store the details in ArrayList * */ public ArrayList<HashMap<String, String>> getPlayList(){ File home = new File(MEDIA_PATH); if (home.listFiles(new FileExtensionFilter()).length > 0) { for (File file : home.listFiles(new FileExtensionFilter())) { HashMap<String, String> song = new HashMap<String, String>(); song.put("songTitle", file.getName().substring(0, (file.getName().length() - 4))); song.put("songPath", file.getPath()); // Adding each song to SongList songsList.add(song); } } // return songs list array return songsList; } /** * Class to filter files which are having .mp3 extension * */ class FileExtensionFilter implements FilenameFilter { public boolean accept(File dir, String name) { return (name.endsWith(".mp3") || name.endsWith(".MP3")); } } }
8. Writing Class for PlayList ListView
Create a new Activity class for playlist listview. Name the file as PlayListActivity.java This class will display list of songs in list layout by using SongsManager.java class
package com.androidhive.musicplayer; import java.util.ArrayList; import java.util.HashMap; import android.app.ListActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.SimpleAdapter; public class PlayListActivity extends ListActivity { // Songs list public ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.playlist); ArrayList<HashMap<String, String>> songsListData = new ArrayList<HashMap<String, String>>(); SongsManager plm = new SongsManager(); // get all songs from sdcard this.songsList = plm.getPlayList(); // looping through playlist for (int i = 0; i < songsList.size(); i++) { // creating new HashMap HashMap<String, String> song = songsList.get(i); // adding HashList to ArrayList songsListData.add(song); } // Adding menuItems to ListView ListAdapter adapter = new SimpleAdapter(this, songsListData, R.layout.playlist_item, new String[] { "songTitle" }, new int[] { R.id.songTitle }); setListAdapter(adapter); // selecting single ListView item ListView lv = getListView(); // listening to single listitem click lv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // getting listitem index int songIndex = position; // Starting new intent Intent in = new Intent(getApplicationContext(), AndroidBuildingMusicPlayerActivity.class); // Sending songIndex to PlayerActivity in.putExtra("songIndex", songIndex); setResult(100, in); // Closing PlayListView finish(); } }); } }
9. Helper Class functions
Create a new class called Utilities.java for handling extra work like converting time to progress percentage and vice-versa. Also it has function to convert millisecond to a timer string which will displayed on the seekbar of the player.
package com.androidhive.musicplayer; public class Utilities { /** * Function to convert milliseconds time to * Timer Format * Hours:Minutes:Seconds * */ public String milliSecondsToTimer(long milliseconds){ String finalTimerString = ""; String secondsString = ""; // Convert total duration into time int hours = (int)( milliseconds / (1000*60*60)); int minutes = (int)(milliseconds % (1000*60*60)) / (1000*60); int seconds = (int) ((milliseconds % (1000*60*60)) % (1000*60) / 1000); // Add hours if there if(hours > 0){ finalTimerString = hours + ":"; } // Prepending 0 to seconds if it is one digit if(seconds < 10){ secondsString = "0" + seconds; }else{ secondsString = "" + seconds;} finalTimerString = finalTimerString + minutes + ":" + secondsString; // return timer string return finalTimerString; } /** * Function to get Progress percentage * @param currentDuration * @param totalDuration * */ public int getProgressPercentage(long currentDuration, long totalDuration){ Double percentage = (double) 0; long currentSeconds = (int) (currentDuration / 1000); long totalSeconds = (int) (totalDuration / 1000); // calculating percentage percentage =(((double)currentSeconds)/totalSeconds)*100; // return percentage return percentage.intValue(); } /** * Function to change progress to timer * @param progress - * @param totalDuration * returns current duration in milliseconds * */ public int progressToTimer(int progress, int totalDuration) { int currentDuration = 0; totalDuration = (int) (totalDuration / 1000); currentDuration = (int) ((((double)progress) / 100) * totalDuration); // return current duration in milliseconds return currentDuration * 1000; } }
7. Writing Classes needed for Audio Player
Open your main activity class which deals with main player interface and make the class implements from OnCompletionListener, SeekBar.OnSeekBarChangeListener.
In this case my main activity name is AndroidBuildingMusicPlayerActivity.
public class AndroidBuildingMusicPlayerActivity extends Activity implements OnCompletionListener, SeekBar.OnSeekBarChangeListener {
Now declare all variable needed for this audio player class.
public class AndroidBuildingMusicPlayerActivity extends Activity implements OnCompletionListener, SeekBar.OnSeekBarChangeListener { private ImageButton btnPlay; private ImageButton btnForward; private ImageButton btnBackward; private ImageButton btnNext; private ImageButton btnPrevious; private ImageButton btnPlaylist; private ImageButton btnRepeat; private ImageButton btnShuffle; private SeekBar songProgressBar; private TextView songTitleLabel; private TextView songCurrentDurationLabel; private TextView songTotalDurationLabel; // Media Player private MediaPlayer mp; // Handler to update UI timer, progress bar etc,. private Handler mHandler = new Handler();; private SongsManager songManager; private Utilities utils; private int seekForwardTime = 5000; // 5000 milliseconds private int seekBackwardTime = 5000; // 5000 milliseconds private int currentSongIndex = 0; private boolean isShuffle = false; private boolean isRepeat = false; private ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();
Now reference all buttons, images from xml layout to class.
// All player buttons btnPlay = (ImageButton) findViewById(R.id.btnPlay); btnForward = (ImageButton) findViewById(R.id.btnForward); btnBackward = (ImageButton) findViewById(R.id.btnBackward); btnNext = (ImageButton) findViewById(R.id.btnNext); btnPrevious = (ImageButton) findViewById(R.id.btnPrevious); btnPlaylist = (ImageButton) findViewById(R.id.btnPlaylist); btnRepeat = (ImageButton) findViewById(R.id.btnRepeat); btnShuffle = (ImageButton) findViewById(R.id.btnShuffle); songProgressBar = (SeekBar) findViewById(R.id.songProgressBar); songTitleLabel = (TextView) findViewById(R.id.songTitle); songCurrentDurationLabel = (TextView) findViewById(R.id.songCurrentDurationLabel); songTotalDurationLabel = (TextView) findViewById(R.id.songTotalDurationLabel); // Mediaplayer mp = new MediaPlayer(); songManager = new SongsManager(); utils = new Utilities(); // Listeners songProgressBar.setOnSeekBarChangeListener(this); // Important mp.setOnCompletionListener(this); // Important // Getting all songs list songsList = songManager.getPlayList();
Launching PlayList
Write click event listener to playlist button. On clicking playlist button we need to launch PlayListAcitivity.java and from listview on selecting a particular song we need get songIndex.
/** * Button Click event for Play list click event * Launches list activity which displays list of songs * */ btnPlaylist.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { Intent i = new Intent(getApplicationContext(), PlayListActivity.class); startActivityForResult(i, 100); } });
To receive the selected songIndex add following fucntion. (Make sure that you added this function outside of onCreate method)
/** * Receiving song index from playlist view * and play the song * */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(resultCode == 100){ currentSongIndex = data.getExtras().getInt("songIndex"); // play selected song playSong(currentSongIndex); } }
Playing Song
Add the following function to your class. This function accepts songIndex as param and plays it. Also when start playing a song it switches the play button to pause button state.
/** * Function to play a song * @param songIndex - index of song * */ public void playSong(int songIndex){ // Play song try { mp.reset(); mp.setDataSource(songsList.get(songIndex).get("songPath")); mp.prepare(); mp.start(); // Displaying Song title String songTitle = songsList.get(songIndex).get("songTitle"); songTitleLabel.setText(songTitle); // Changing Button Image to pause image btnPlay.setImageResource(R.drawable.btn_pause); // set Progress bar values songProgressBar.setProgress(0); songProgressBar.setMax(100); // Updating progress bar updateProgressBar(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
Forward / Backward button click events
Add event listeners to Forward and Backward buttons which forwards or backwards song by specified seconds.
Forward button click event – moves song to specified number of seconds forward
/** * Forward button click event * Forwards song specified seconds * */ btnForward.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // get current song position int currentPosition = mp.getCurrentPosition(); // check if seekForward time is lesser than song duration if(currentPosition + seekForwardTime <= mp.getDuration()){ // forward song mp.seekTo(currentPosition + seekForwardTime); }else{ // forward to end position mp.seekTo(mp.getDuration()); } } });
Backward button click event – moves song to specified number of seconds backward
/** * Backward button click event * Backward song to specified seconds * */ btnBackward.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // get current song position int currentPosition = mp.getCurrentPosition(); // check if seekBackward time is greater than 0 sec if(currentPosition - seekBackwardTime >= 0){ // forward song mp.seekTo(currentPosition - seekBackwardTime); }else{ // backward to starting position mp.seekTo(0); } } });
Next / Back button click events
Add click listeners to next and back buttons.
Next button click event – which plays next song from the playlist if presents else plays first song
/** * Next button click event * Plays next song by taking currentSongIndex + 1 * */ btnNext.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // check if next song is there or not if(currentSongIndex < (songsList.size() - 1)){ playSong(currentSongIndex + 1); currentSongIndex = currentSongIndex + 1; }else{ // play first song playSong(0); currentSongIndex = 0; } } });
Back button click event – which plays previous song if presents or plays last song
/** * Back button click event * Plays previous song by currentSongIndex - 1 * */ btnPrevious.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { if(currentSongIndex > 0){ playSong(currentSongIndex - 1); currentSongIndex = currentSongIndex - 1; }else{ // play last song playSong(songsList.size() - 1); currentSongIndex = songsList.size() - 1; } } });
Updating SeekBar progress and Timer
To update progress bar timer i implemented a background thread which runs in background using a Handler. If you new to Handler follow this doc. Updating the UI from a Timer
/** * Update timer on seekbar * */ public void updateProgressBar() { mHandler.postDelayed(mUpdateTimeTask, 100); } /** * Background Runnable thread * */ private Runnable mUpdateTimeTask = new Runnable() { public void run() { long totalDuration = mp.getDuration(); long currentDuration = mp.getCurrentPosition(); // Displaying Total Duration time songTotalDurationLabel.setText(""+utils.milliSecondsToTimer(totalDuration)); // Displaying time completed playing songCurrentDurationLabel.setText(""+utils.milliSecondsToTimer(currentDuration)); // Updating progress bar int progress = (int)(utils.getProgressPercentage(currentDuration, totalDuration)); //Log.d("Progress", ""+progress); songProgressBar.setProgress(progress); // Running this thread after 100 milliseconds mHandler.postDelayed(this, 100); } }; /** * * */ @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { } /** * When user starts moving the progress handler * */ @Override public void onStartTrackingTouch(SeekBar seekBar) { // remove message Handler from updating progress bar mHandler.removeCallbacks(mUpdateTimeTask); } /** * When user stops moving the progress hanlder * */ @Override public void onStopTrackingTouch(SeekBar seekBar) { mHandler.removeCallbacks(mUpdateTimeTask); int totalDuration = mp.getDuration(); int currentPosition = utils.progressToTimer(seekBar.getProgress(), totalDuration); // forward or backward to certain seconds mp.seekTo(currentPosition); // update timer progress again updateProgressBar(); }
Repeat button click event
On clicking repeat button we need to set isRepeat to true and vice-versa. Also we need to change image source of repeat button to focused state.
/** * Button Click event for Repeat button * Enables repeat flag to true * */ btnRepeat.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { if(isRepeat){ isRepeat = false; Toast.makeText(getApplicationContext(), "Repeat is OFF", Toast.LENGTH_SHORT).show(); btnRepeat.setImageResource(R.drawable.btn_repeat); }else{ // make repeat to true isRepeat = true; Toast.makeText(getApplicationContext(), "Repeat is ON", Toast.LENGTH_SHORT).show(); // make shuffle to false isShuffle = false; btnRepeat.setImageResource(R.drawable.btn_repeat_focused); btnShuffle.setImageResource(R.drawable.btn_shuffle); } } });
Shuffle button click event
On clicking shuffle button we need to set isShuffle to true and vice-versa. Also we need to change image source of shuffle button to focused state.
/** * Button Click event for Shuffle button * Enables shuffle flag to true * */ btnShuffle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { if(isShuffle){ isShuffle = false; Toast.makeText(getApplicationContext(), "Shuffle is OFF", Toast.LENGTH_SHORT).show(); btnShuffle.setImageResource(R.drawable.btn_shuffle); }else{ // make repeat to true isShuffle= true; Toast.makeText(getApplicationContext(), "Shuffle is ON", Toast.LENGTH_SHORT).show(); // make shuffle to false isRepeat = false; btnShuffle.setImageResource(R.drawable.btn_shuffle_focused); btnRepeat.setImageResource(R.drawable.btn_repeat); } } });
Implementing song onCompletion Listener
It is important to implement this listener which will notify you once the song is completed playing. In this method we need to play next song automatically depending on repeat and shuffle conditions.
/** * On Song Playing completed * if repeat is ON play same song again * if shuffle is ON play random song * */ @Override public void onCompletion(MediaPlayer arg0) { // check for repeat is ON or OFF if(isRepeat){ // repeat is on play same song again playSong(currentSongIndex); } else if(isShuffle){ // shuffle is on - play a random song Random rand = new Random(); currentSongIndex = rand.nextInt((songsList.size() - 1) - 0 + 1) + 0; playSong(currentSongIndex); } else{ // no repeat or shuffle ON - play next song if(currentSongIndex < (songsList.size() - 1)){ playSong(currentSongIndex + 1); currentSongIndex = currentSongIndex + 1; }else{ // play first song playSong(0); currentSongIndex = 0; } } }
Update your AndroidManifest.xml
Update your AndroidManifest.xml to following code. Add android:configChanges=”keyboardHidden|orientation” to your main activity node.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androidhive.musicplayer" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".AndroidBuildingMusicPlayerActivity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".PlayListActivity" /> </application> </manifest> <!-- AndroidBuildingMusicPlayerActivity -->
Final Code
Following is complete code for the AndroidBuildingMusicPlayerActivity.java class.
package com.androidhive.musicplayer; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Random; import android.app.Activity; import android.content.Intent; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.ImageButton; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; public class AndroidBuildingMusicPlayerActivity extends Activity implements OnCompletionListener, SeekBar.OnSeekBarChangeListener { private ImageButton btnPlay; private ImageButton btnForward; private ImageButton btnBackward; private ImageButton btnNext; private ImageButton btnPrevious; private ImageButton btnPlaylist; private ImageButton btnRepeat; private ImageButton btnShuffle; private SeekBar songProgressBar; private TextView songTitleLabel; private TextView songCurrentDurationLabel; private TextView songTotalDurationLabel; // Media Player private MediaPlayer mp; // Handler to update UI timer, progress bar etc,. private Handler mHandler = new Handler();; private SongsManager songManager; private Utilities utils; private int seekForwardTime = 5000; // 5000 milliseconds private int seekBackwardTime = 5000; // 5000 milliseconds private int currentSongIndex = 0; private boolean isShuffle = false; private boolean isRepeat = false; private ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.player); // All player buttons btnPlay = (ImageButton) findViewById(R.id.btnPlay); btnForward = (ImageButton) findViewById(R.id.btnForward); btnBackward = (ImageButton) findViewById(R.id.btnBackward); btnNext = (ImageButton) findViewById(R.id.btnNext); btnPrevious = (ImageButton) findViewById(R.id.btnPrevious); btnPlaylist = (ImageButton) findViewById(R.id.btnPlaylist); btnRepeat = (ImageButton) findViewById(R.id.btnRepeat); btnShuffle = (ImageButton) findViewById(R.id.btnShuffle); songProgressBar = (SeekBar) findViewById(R.id.songProgressBar); songTitleLabel = (TextView) findViewById(R.id.songTitle); songCurrentDurationLabel = (TextView) findViewById(R.id.songCurrentDurationLabel); songTotalDurationLabel = (TextView) findViewById(R.id.songTotalDurationLabel); // Mediaplayer mp = new MediaPlayer(); songManager = new SongsManager(); utils = new Utilities(); // Listeners songProgressBar.setOnSeekBarChangeListener(this); // Important mp.setOnCompletionListener(this); // Important // Getting all songs list songsList = songManager.getPlayList(); // By default play first song playSong(0); /** * Play button click event * plays a song and changes button to pause image * pauses a song and changes button to play image * */ btnPlay.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // check for already playing if(mp.isPlaying()){ if(mp!=null){ mp.pause(); // Changing button image to play button btnPlay.setImageResource(R.drawable.btn_play); } }else{ // Resume song if(mp!=null){ mp.start(); // Changing button image to pause button btnPlay.setImageResource(R.drawable.btn_pause); } } } }); /** * Forward button click event * Forwards song specified seconds * */ btnForward.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // get current song position int currentPosition = mp.getCurrentPosition(); // check if seekForward time is lesser than song duration if(currentPosition + seekForwardTime <= mp.getDuration()){ // forward song mp.seekTo(currentPosition + seekForwardTime); }else{ // forward to end position mp.seekTo(mp.getDuration()); } } }); /** * Backward button click event * Backward song to specified seconds * */ btnBackward.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // get current song position int currentPosition = mp.getCurrentPosition(); // check if seekBackward time is greater than 0 sec if(currentPosition - seekBackwardTime >= 0){ // forward song mp.seekTo(currentPosition - seekBackwardTime); }else{ // backward to starting position mp.seekTo(0); } } }); /** * Next button click event * Plays next song by taking currentSongIndex + 1 * */ btnNext.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // check if next song is there or not if(currentSongIndex < (songsList.size() - 1)){ playSong(currentSongIndex + 1); currentSongIndex = currentSongIndex + 1; }else{ // play first song playSong(0); currentSongIndex = 0; } } }); /** * Back button click event * Plays previous song by currentSongIndex - 1 * */ btnPrevious.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { if(currentSongIndex > 0){ playSong(currentSongIndex - 1); currentSongIndex = currentSongIndex - 1; }else{ // play last song playSong(songsList.size() - 1); currentSongIndex = songsList.size() - 1; } } }); /** * Button Click event for Repeat button * Enables repeat flag to true * */ btnRepeat.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { if(isRepeat){ isRepeat = false; Toast.makeText(getApplicationContext(), "Repeat is OFF", Toast.LENGTH_SHORT).show(); btnRepeat.setImageResource(R.drawable.btn_repeat); }else{ // make repeat to true isRepeat = true; Toast.makeText(getApplicationContext(), "Repeat is ON", Toast.LENGTH_SHORT).show(); // make shuffle to false isShuffle = false; btnRepeat.setImageResource(R.drawable.btn_repeat_focused); btnShuffle.setImageResource(R.drawable.btn_shuffle); } } }); /** * Button Click event for Shuffle button * Enables shuffle flag to true * */ btnShuffle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { if(isShuffle){ isShuffle = false; Toast.makeText(getApplicationContext(), "Shuffle is OFF", Toast.LENGTH_SHORT).show(); btnShuffle.setImageResource(R.drawable.btn_shuffle); }else{ // make repeat to true isShuffle= true; Toast.makeText(getApplicationContext(), "Shuffle is ON", Toast.LENGTH_SHORT).show(); // make shuffle to false isRepeat = false; btnShuffle.setImageResource(R.drawable.btn_shuffle_focused); btnRepeat.setImageResource(R.drawable.btn_repeat); } } }); /** * Button Click event for Play list click event * Launches list activity which displays list of songs * */ btnPlaylist.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { Intent i = new Intent(getApplicationContext(), PlayListActivity.class); startActivityForResult(i, 100); } }); } /** * Receiving song index from playlist view * and play the song * */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(resultCode == 100){ currentSongIndex = data.getExtras().getInt("songIndex"); // play selected song playSong(currentSongIndex); } } /** * Function to play a song * @param songIndex - index of song * */ public void playSong(int songIndex){ // Play song try { mp.reset(); mp.setDataSource(songsList.get(songIndex).get("songPath")); mp.prepare(); mp.start(); // Displaying Song title String songTitle = songsList.get(songIndex).get("songTitle"); songTitleLabel.setText(songTitle); // Changing Button Image to pause image btnPlay.setImageResource(R.drawable.btn_pause); // set Progress bar values songProgressBar.setProgress(0); songProgressBar.setMax(100); // Updating progress bar updateProgressBar(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * Update timer on seekbar * */ public void updateProgressBar() { mHandler.postDelayed(mUpdateTimeTask, 100); } /** * Background Runnable thread * */ private Runnable mUpdateTimeTask = new Runnable() { public void run() { long totalDuration = mp.getDuration(); long currentDuration = mp.getCurrentPosition(); // Displaying Total Duration time songTotalDurationLabel.setText(""+utils.milliSecondsToTimer(totalDuration)); // Displaying time completed playing songCurrentDurationLabel.setText(""+utils.milliSecondsToTimer(currentDuration)); // Updating progress bar int progress = (int)(utils.getProgressPercentage(currentDuration, totalDuration)); //Log.d("Progress", ""+progress); songProgressBar.setProgress(progress); // Running this thread after 100 milliseconds mHandler.postDelayed(this, 100); } }; /** * * */ @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { } /** * When user starts moving the progress handler * */ @Override public void onStartTrackingTouch(SeekBar seekBar) { // remove message Handler from updating progress bar mHandler.removeCallbacks(mUpdateTimeTask); } /** * When user stops moving the progress hanlder * */ @Override public void onStopTrackingTouch(SeekBar seekBar) { mHandler.removeCallbacks(mUpdateTimeTask); int totalDuration = mp.getDuration(); int currentPosition = utils.progressToTimer(seekBar.getProgress(), totalDuration); // forward or backward to certain seconds mp.seekTo(currentPosition); // update timer progress again updateProgressBar(); } /** * On Song Playing completed * if repeat is ON play same song again * if shuffle is ON play random song * */ @Override public void onCompletion(MediaPlayer arg0) { // check for repeat is ON or OFF if(isRepeat){ // repeat is on play same song again playSong(currentSongIndex); } else if(isShuffle){ // shuffle is on - play a random song Random rand = new Random(); currentSongIndex = rand.nextInt((songsList.size() - 1) - 0 + 1) + 0; playSong(currentSongIndex); } else{ // no repeat or shuffle ON - play next song if(currentSongIndex < (songsList.size() - 1)){ playSong(currentSongIndex + 1); currentSongIndex = currentSongIndex + 1; }else{ // play first song playSong(0); currentSongIndex = 0; } } } @Override public void onDestroy(){ super.onDestroy(); mp.release(); } }
Sending files to Emulator SDCard (For Testing)
To test this app in your android emulator you need to load your emulator with some songs. You can send files to emulator sdcard using adb tool which comes with Android SDK.
Navigate to your android SDK folder/platform-tools/ using command line. And using push command you can send files to sdcard. (Start your emulator before performing push command)
platform-tools> adb push "c:\Songs\White Flag.mp3" "/sdcard/"
Run your application.
Hi there! I am Founder at androidhive and programming enthusiast. My skills includes Android, iOS, PHP, Ruby on Rails and lot more. If you have any idea that you would want me to develop? Let’s talk: ravi@androidhive.info
I have written a method to scan any folder, including all its subfolders for all files matching any wanted file extension.
You can find the code here:
http://pastebin.com/krxV64R3
The method “createAudioExtensionsList()” creates a list of file extensions that you want to find. In your case that would only be mp3 files so you have to remove the other entries.
“getFileExtension(…)” is a simple method to get the extension of a file.
“getFilesInFolder(…)” is a function that calls itself recursively to scan a folder and all its subfolders for the file with the extensions that you give it as parameters. If you want to scan the whole sdcard you just pass the that to the function! (be aware that different Android ROMs might have different naming conventions! There is a method to get the root path of the sd card but I dont remember, so you have to look it up yourself)
Hi Mr.bowter…thank u so much fr yr reply..but the Url which u have given is not working..i couldn’t able to connect to that site…can u pls check out n let me know the code..Thank u once again…Waiting for yr reply….
I already tried it, but I can’t call the function “getFilesInFolder”. Eclipse keep saying ” The method getFilesInFolder(File, ArrayList) in the type SongsManager is not applicable for the arguments (String,
ArrayList)”. Can you please help me? Thank you.
see the post above, I’ve posted something that works for me :]
Is there someone who is willing to send source code for android music player that runs smoothly. I would be very grateful to those of you who have helped me. you can get sent to the email: ceo.revoseven @ gmail.com. thanks before
hii…i need the same.plz send me on priyanka.gulati07@gmail.com
how…what was d problem?
Hai Ravi.
How to get mp3 songs Thumbnail from sdcard in android.
Hello. Thanks for the tutorial! But I think that there is better way to find songs in the phone. You can find it like that:
public ArrayList<HashMap> getPlayList(){
Cursor cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, new String [] {“ARTIST”, “DURATION”, “TITLE”, “_DATA”, “ALBUM”}, null, null, null);
while(cursor.moveToNext()) {
HashMap song = new HashMap();
song.put(“artist”, cursor.getString(0));
song.put(“duration”, cursor.getString(1));
song.put(“songTitle”, cursor.getString(2));
song.put(“songPath”,cursor.getString(3));
song.put(“album”,cursor.getString(4));
// Adding each song to SongList
songsList.add(song);
}
return songsList;
}
Thanks to this you can also get name of artists, albums and duration.
this code isn’t working for me. Is there anything that has to be changed for it to work?
Ok, now i see. When i shared it this site change a bit of code. So you have to download it from here: https://docs.google.com/document/d/1QIUZBGkSKfygvdyGJ5QOSaOlMsmxsZ9Lp0uNZ1-LZKk/edit?usp=sharing
In “Cursor cursor = resolver.query(…..” What is “resolver”? Is it a variable or a constant. And how do I initialize it? Thanks in advance.
For anyone having trouble with the IndexOutOfBoundsException, it is because it is not finding any music on your sdcard.
Line 80: playSong(0); throws an indexOutBoundsException when it finds no music (getPlaylist() returns a blank list so 0 is not a proper index).
I fixed it by changing the the directory it starts in so it actually finds music. Here is a code snippet to set the directory as the music folder. Make sure you actually have music there or you’ll still get the error.
In SongsManager.java: getPlaylist() method:
File home = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
The original tutorial probably should have a had check on the size to make sure the playlist really had something in it rather than trying to play the first song off the bat which crashes the program if no music exists.
if(songsList.size() >0){
// By default play first song
playSong(0);
}
It is not finding music on your sdcard. In the class AndroidBuildingMusicPlayerActivity, it attempts to playSong(0). If the songsManager finds no music, this will throw that exception. You can either change where it is looking for music or prevent the app from playing the first song. See my post at the top.
how building audio list from web service, any help?
Man its an error during parsing sdcard for mp3 files.
please do correct it. Its in the fuctiongetplaylist in SongsManager
hey grt work …..
can u help with my app coz i have to build an audio player which instead of using the plugins use decoding, i.e it is more of decoder bt i dont how to implement it in android
if u geted message ” forced to close” u change android:name=”.AndroidBuildingMusicPlayerActivity” to android:name=”com.androidhive.musicplayer.AndroidBuildingMusicPlayerActivity”
i done
For me no done can you help me
thank
For me no done
can you help me please
thank
i think the the problem is that you dont have any mp3 on device. And app plays first song on start but doesnt find it ;P
Did you correct the force close error in the app.
if you did please share how..
you have to have mp3 music in emulator device.
Thanks for making such a great job. However, I have these problems in eclipse when I run the player as android application on my PC. Please help me fix these errors.
04-24 18:26:22.245: E/Trace(790): error opening trace file: No such file or directory (2)
04-24 18:26:23.095: D/dalvikvm(790): GC_FOR_ALLOC freed 73K, 8% free 2527K/2724K, paused 47ms, total 50ms
04-24 18:26:23.225: D/dalvikvm(790): GC_CONCURRENT freed 5K, 6% free 2972K/3148K, paused 19ms+9ms, total 75ms
04-24 18:26:23.225: D/dalvikvm(790): WAIT_FOR_CONCURRENT_GC blocked 4ms
04-24 18:26:23.435: D/AndroidRuntime(790): Shutting down VM
04-24 18:26:23.435: W/dalvikvm(790): threadid=1: thread exiting with uncaught exception (group=0x40a71930)
04-24 18:26:23.476: E/AndroidRuntime(790): FATAL EXCEPTION: main
04-24 18:26:23.476: E/AndroidRuntime(790): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.rajumediaplayer/com.rajumediaplayer.RajuMediaPlayer}: java.lang.NullPointerException
04-24 18:26:23.476: E/AndroidRuntime(790): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
04-24 18:26:23.476: E/AndroidRuntime(790): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
04-24 18:26:23.476: E/AndroidRuntime(790): at android.app.ActivityThread.access$600(ActivityThread.java:141)
04-24 18:26:23.476: E/AndroidRuntime(790): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
04-24 18:26:23.476: E/AndroidRuntime(790): at android.os.Handler.dispatchMessage(Handler.java:99)
04-24 18:26:23.476: E/AndroidRuntime(790): at android.os.Looper.loop(Looper.java:137)
04-24 18:26:23.476: E/AndroidRuntime(790): at android.app.ActivityThread.main(ActivityThread.java:5041)
04-24 18:26:23.476: E/AndroidRuntime(790): at java.lang.reflect.Method.invokeNative(Native Method)
04-24 18:26:23.476: E/AndroidRuntime(790): at java.lang.reflect.Method.invoke(Method.java:511)
04-24 18:26:23.476: E/AndroidRuntime(790): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
04-24 18:26:23.476: E/AndroidRuntime(790): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
04-24 18:26:23.476: E/AndroidRuntime(790): at dalvik.system.NativeStart.main(Native Method)
04-24 18:26:23.476: E/AndroidRuntime(790): Caused by: java.lang.NullPointerException
04-24 18:26:23.476: E/AndroidRuntime(790): at com.rajumediaplayer.SongsManager.getPlayList(SongsManager.java:24)
04-24 18:26:23.476: E/AndroidRuntime(790): at com.rajumediaplayer.RajuMediaPlayer.onCreate(RajuMediaPlayer.java:76)
04-24 18:26:23.476: E/AndroidRuntime(790): at android.app.Activity.performCreate(Activity.java:5104)
04-24 18:26:23.476: E/AndroidRuntime(790): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
04-24 18:26:23.476: E/AndroidRuntime(790): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
04-24 18:26:23.476: E/AndroidRuntime(790): … 11 more
04-24 18:26:23.715: D/dalvikvm(790): GC_CONCURRENT freed 57K, 6% free 3316K/3496K, paused 17ms+4ms, total 237ms
04-24 18:26:28.282: I/Process(790): Sending signal. PID: 790 SIG: 9
Hi Ravi,
your code works like charm. Now I have song array list which came through server and populated in list view.I want to implement my codes with your music player,so that I have been looking through your codes and fount out MEDIA_PATH string which is pointed to sdcard. My question is that how could I change this path to load my songs list array properly ? Thanks in advance !
Download song list xml file and parse it search xml parsing tutorial on same website
i cant download the code 🙁
ok i download the code and testing in my nexus isnt working the folder stuff, and could be a slow task i guess scanning so in song manager i changed this:
public ArrayList<HashMap> getPlayList(Context context){
String[] projection = {
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DURATION
};
String selection = MediaStore.Audio.Media.IS_MUSIC + ” != 0″;
Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
null);
if(cursor!=null)
{
while(cursor.moveToNext()) {
HashMap song = new HashMap();
String title = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
song.put(“songTitle”, title);
song.put(“songPath”, path);
songsList.add(song);
}
}
return songsList;
}
thumps up
I’m unable to implement your code. Could you please post whole code for SongManager. Thanks!
Thank you for this interesting application.
however when I started to run it / launch it.. it shows “You project contains error(s) , Please fix them before running the application”…
I recheck all lines in all imported files and found some in the Utilities.java
Implicit super constructor Object() is undefined for default constructor. Must define an explicit constructor
and for string declaration, I got: String cannot be resolved to a type
I tried to solve it in different ways with no results
thank you helping
It is showing content is not allowed in prolog error
Error:
Description Resource Path Location Type
Parser exception for /AlphaMusicPlayer/AndroidManifest.xml: The processing instruction target matching “[xX][mM][lL]” is not allowed. AlphaMusicPlayer line 1 Android ADT Problem
This is the manifest file and it is showing me the ADT problem. I couldn’t find any answer. I would be obliged if anyone can help me fix it? D:
This is just what I was looking for. Thansk you so much…
Hi, Thanks for the code, it works best for .mp3 files. But when I tried to play .wav file the seek to feature is not working properly. Do you know/have any workaround for this issue?
Simple question.
On which Android API does this run?
I mean the version.
Hi ravi
right now your taking the files by “SDCARD” , if it is url based how to play… please explain this.
Hi
Thank you for tutorials
I want to ask you while i ran this apps it show me a message Force Close
I don’t know what’s wrong
Please help me to solve this problem
thank
I have an error, help please!!

thanks
To fix error simply add final String MEDIA_PATH = new String(Environment.getExternalStorageDirectory().getPath() +”/sdcard/”);
in song manger then create sdcard folder in your external storage and add songs in it install and tada!!!!!!!
i’ve an error message.
Unfonately AndroidBuildingMusicPlayer has stopped…
but there’s no such error in your coding
please help me
To fix error simply add final String MEDIA_PATH = new String(Environment.getExternalStorageDirectory().getPath() +”/sdcard/”);
in song manger then create sdcard folder in your external storage and add songs in it install and tada!!!!!!!1
I am loving AndroidHive because of so descriptive UI designing tutorial.. :thumbsup:
Keep up the good work.. Helped me learn how to design the UI…
Hi!! Great tutorial.can you explain me how to create a series of playlist and pick one of them to play?
Thank You very much. Great help 🙂
hey ! great post but i was not able to login into your download section and download the code. because i never recieved the subscription confirmation email. please cehck . Thanks . Cheers ! 😀
Hi Ravi,
Thanks for this tutorial, I got it working. I have a concern though, the stack trace displays a lot of logs from the constant checking of getDuration and getCurrentPosition. If however someone uses this for a bigger application, I wanted to stop the checking after I’m done or stopped the media player. If someone has resolved this or will resolve this, please let me know. Thanks a lot.
Where should you put this codes? I am new to android and so would appreciate the help. Thank you.
Would you know where to add the codes stated by MarioB? I’m still learning and don’t know exactly what to look for. Thank you.
Hey thanks for the great tutorial.I am just a noob and want to learn android programming.I have got a force close issue and i dont know how to deal with this so can anyone please help me out!!
i got the same kind of problem.if you find any solution please let me know
rand.nextInt((songsList.size() – 1) – 0 + 1) + 0 What is it?
currentSongIndex = rand.nextInt((songsList.size() – 1) – 0 + 1) + 0;
What is it?
Hi all. If I need timer to close this app. What is technique I should use???
I need to close this app with specific time. What is technique I should use?
thanks
Thanks for Great Tutorial.
i have 10 songs in raw folder . how can i show in a listview.
all songs from raw folder in listview.
please tell to me how change “playlist.java” for read songs from raw folder
Edit…
Thanks for Great Tutorial.
i have 10 songs in raw folder . how can i show in a listview.
all songs from raw folder in listview.
please tell to me how change “SongsManager.java” for read songs from raw folder
HI Ravi
How to change the path to link ( URL )
final String MEDIA_PATH = new String(“/sdcard/”);
To fix error simply add final String MEDIA_PATH = new String(Environment.getExternalStorageDirectory().getPath() +”/sdcard/”);
in song manger then create sdcard folder in your external storage and add songs in it install and tada!!!!!!!23
How to download a file mp3 throught a path link on internet in android.Please help me.
hello, nice one working i want dowanload this code ? how if is it possible so plese send me link or option for download this audio player tutoriacl code
Hi I want to ask you how to design next/back buttons to get list of items from data base please.
MEDIA_PATH in SongsManager.java is set to “/sdcard/” which might not be the correct path.
In my case I set it to “/storage/emlated/0/Music” and everything works fine.
It plays the music as soon as it starts so incorrect path leads to Force Close
Hey, how do you make it so that the program looks for all the MP3 files in the android device rather than in a directory?
Sir its very Good Tutorial, but When I stop the song and press the back button of the emulator the application Crashes every time. I Tried many times to correct it by using other methods but it continues Crashing on exit or back button?
Kindly Help me
mHandler.removeCallbacks(mUpdateTimeTask);