Showing posts with label MP3 Player. Show all posts
Showing posts with label MP3 Player. Show all posts

Implement time bar for MediaPlayer, also introduce bug of MediaPlayer.seekTo()

Continuous from last post of MediaPlay MP3 Player, a SeekBar is added to show the current playing position.

Also user can seek to a specified time by moving the SeekBar, by calling seekTo() of MediaPlayer. But the seekTo() method work in Nexus One (Android 2.3.6), not work on Nexus 7 1st generation (Android 4.4.2). It seem to be a bug!


Modify fragment_main.xml to add a SeekBar.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.androidmp3player.MainActivity$PlaceholderFragment" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://arteluzevida.blogspot.com/"
android:textStyle="bold" />

<Button
android:id="@+id/start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start" />
<Button
android:id="@+id/pause"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pause" />
<Button
android:id="@+id/stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Stop" />
<Button
android:id="@+id/seekto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Seek To Beginning" />
<SeekBar
android:id="@+id/time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="0"/>
<TextView
android:id="@+id/state"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/duration"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/position"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</LinearLayout>


MainActivity.java
package com.example.androidmp3player;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnSeekCompleteListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}

/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {

Button btnStart, btnPause, btnStop, btnSeek;
TextView textState, textDuration, textPosition;
SeekBar timeBar;

MediaPlayer mediaPlayer;

private int stateMediaPlayer;
private final int STATE_Idle = 0;
private final int STATE_Initialized = 1;
private final int STATE_Preparing = 2;
private final int STATE_Prepared = 3;
private final int STATE_Started = 4;
private final int STATE_Paused = 5;
private final int STATE_Stopped = 6;
private final int STATE_PlaybackCompleted = 7;
private final int STATE_End = 8;
private final int STATE_Error = 9;

PlayerTimeTask playerTimeTask;

public PlaceholderFragment() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
initMediaPlayer();
playerTimeTask = new PlayerTimeTask();
playerTimeTask.execute();
}

@Override
public void onDestroy() {

playerTimeTask.setRunning(false);

Toast.makeText(getActivity(),
"release mediaPlayer",
Toast.LENGTH_LONG).show();
mediaPlayer.release();
mediaPlayer = null;
setPlayerState(STATE_End);

super.onDestroy();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
btnStart = (Button) rootView.findViewById(R.id.start);
btnPause = (Button) rootView.findViewById(R.id.pause);
btnStop = (Button) rootView.findViewById(R.id.stop);
btnSeek = (Button) rootView.findViewById(R.id.seekto);

btnStart.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.start();
setPlayerState(STATE_Started);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Play at Invalid state!",
Toast.LENGTH_LONG).show();
}
}
});

btnPause.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_Prepared //simulate a error case
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.pause();
setPlayerState(STATE_Paused);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Pause at Invalid state!",
Toast.LENGTH_LONG).show();
}
}
});

btnStop.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Stopped
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){

//Stop
mediaPlayer.stop();
setPlayerState(STATE_Stopped);

//then parepare in background thread
mediaPlayer.prepareAsync();
setPlayerState(STATE_Preparing);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Stop at Invalid state!",
Toast.LENGTH_LONG).show();
}

}
});

btnSeek.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.seekTo(0);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"SeekTo at Invalid state!",
Toast.LENGTH_LONG).show();
}
}});

timeBar = (SeekBar) rootView.findViewById(R.id.time);
timeBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

int targetPos = 0;
boolean rqsSeek = false;

@Override
public void onStopTrackingTouch(SeekBar seekBar) {

if(rqsSeek){

if(mediaPlayer!=null){
if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){

mediaPlayer.seekTo(targetPos);
}
}

rqsSeek = false;
}

}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {}

@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {

if(fromUser){
rqsSeek = true;

if(mediaPlayer!=null){
float seekToPercentage = (float)progress/100.0f;
targetPos = (int)(mediaPlayer.getDuration() * seekToPercentage);
}
}

}
});

textState = (TextView) rootView.findViewById(R.id.state);
textState.setText(getPlayerState());

textDuration = (TextView) rootView.findViewById(R.id.duration);
textPosition = (TextView) rootView.findViewById(R.id.position);
displayDurationPosition();

textDuration.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
displayDurationPosition();
}});

textPosition.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
displayDurationPosition();
}});

return rootView;
}

private void displayDurationPosition(){
textDuration.setText(
"Duration: " + mediaPlayer.getDuration() + " ms");
textPosition.setText(
"Current Position: " + mediaPlayer.getCurrentPosition() + " ms");
}

private void initMediaPlayer() {
Toast.makeText(getActivity(),
"initMediaPlayer()",
Toast.LENGTH_LONG).show();
mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);
setPlayerState(STATE_Prepared);

mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

@Override
public void onPrepared(MediaPlayer mp) {
setPlayerState(STATE_Prepared);
displayDurationPosition();
}});

mediaPlayer.setOnCompletionListener(new OnCompletionListener(){

@Override
public void onCompletion(MediaPlayer mp) {
setPlayerState(STATE_PlaybackCompleted);
displayDurationPosition();
}});

//Handle Error
mediaPlayer.setOnErrorListener(new OnErrorListener(){

@Override
public boolean onError(MediaPlayer mp, int what, int extra) {

setPlayerState(STATE_Error);

String errorWhat;
switch(what){
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
errorWhat = "MEDIA_ERROR_UNKNOWN";
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
errorWhat = "MEDIA_ERROR_SERVER_DIED";
break;
default:
errorWhat = "!";
}

String errorExtra;
switch(extra){
case MediaPlayer.MEDIA_ERROR_IO:
errorExtra = "MEDIA_ERROR_IO";
break;
case MediaPlayer.MEDIA_ERROR_MALFORMED:
errorExtra = "MEDIA_ERROR_MALFORMED";
break;
case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
errorExtra = "MEDIA_ERROR_UNSUPPORTED";
break;
case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
errorExtra = "MEDIA_ERROR_TIMED_OUT";
break;
default:
errorExtra = "!";
}

Toast.makeText(getActivity(),
"Error" + "\n"
+ errorWhat + "\n"
+ errorExtra,
Toast.LENGTH_LONG).show();

//release
mp.release();
initMediaPlayer();

return true;
}});

mediaPlayer.setOnSeekCompleteListener(new OnSeekCompleteListener() {

@Override
public void onSeekComplete(MediaPlayer mp) {
Toast.makeText(getActivity(),
"OnSeekComplete: " + mp.getCurrentPosition(),
Toast.LENGTH_SHORT).show();

}
});
}

private void setPlayerState(int st){
stateMediaPlayer = st;

String stringState = getPlayerState();
if(textState!=null){
textState.setText(stringState);
}else{
Toast.makeText(getActivity(),
stringState, Toast.LENGTH_LONG).show();
}

}

private String getPlayerState(){
String strSt;
switch(stateMediaPlayer){
case STATE_Idle:
strSt = "Idle";
break;
case STATE_Initialized:
strSt = "Initialized";
break;
case STATE_Preparing:
strSt = "Preparing";
break;
case STATE_Prepared:
strSt = "Prepared";
break;
case STATE_Started:
strSt = "Started";
break;
case STATE_Paused:
strSt = "Paused";
break;
case STATE_Stopped:
strSt = "Stopped";
break;
case STATE_PlaybackCompleted:
strSt = "PlaybackCompleted";
break;
case STATE_End:
strSt = "End";
break;
case STATE_Error:
strSt = "Error";
break;
default:
strSt = "unknown...";
}
return strSt;
}

public class PlayerTimeTask extends AsyncTask<Void, Void, Void> {

boolean running;

public PlayerTimeTask() {
running = true;
}

public void setRunning(boolean r){
running = r;
}

@Override
protected Void doInBackground(Void... params) {
while(running){
SystemClock.sleep(250);
publishProgress();
}
return null;
}

@Override
protected void onProgressUpdate(Void... values) {
if(timeBar!=null){

if(mediaPlayer!=null){

if(stateMediaPlayer == STATE_Prepared
|| stateMediaPlayer == STATE_Started
|| stateMediaPlayer == STATE_Paused
|| stateMediaPlayer == STATE_Stopped
|| stateMediaPlayer == STATE_PlaybackCompleted){
int cur = mediaPlayer.getCurrentPosition();
int dur = mediaPlayer.getDuration();
int timePercentage = 100 * cur/dur;
timeBar.setProgress(timePercentage);
}

textPosition.setText(
"Current Position: "
+ mediaPlayer.getCurrentPosition() + " ms");
}

}
}


}
}

}


download filesDownload the files, not include mp3.

Downlaod and try the APK.

Re-set On..Listener after mediaPlayer.release and re-create MediaPlayer

It's a BIG bug in last exercise Implement OnErrorListener for MP3 Player using MediaPlayer: after we release the old mediaPlayer, and create again, the original OnPreparedListener(), OnCompletionListener() and OnErrorListener() are not associate with the new mediaPlayer; and will not be called. So we should move all code of setOnPreparedListener(), setOnCompletionListener() and setOnErrorListener() to initMediaPlayer(); to update the Listeners after new mediaPlayer created.

MainActivity.java
package com.example.androidmp3player;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}

/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {

Button btnStart, btnPause, btnStop, btnSeek;
TextView textState, textDuration, textPosition;

MediaPlayer mediaPlayer;

private int stateMediaPlayer;
private final int STATE_Idle = 0;
private final int STATE_Initialized = 1;
private final int STATE_Preparing = 2;
private final int STATE_Prepared = 3;
private final int STATE_Started = 4;
private final int STATE_Paused = 5;
private final int STATE_Stopped = 6;
private final int STATE_PlaybackCompleted = 7;
private final int STATE_End = 8;
private final int STATE_Error = 9;

public PlaceholderFragment() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
initMediaPlayer();
}

@Override
public void onDestroy() {

Toast.makeText(getActivity(),
"release mediaPlayer",
Toast.LENGTH_LONG).show();
mediaPlayer.release();
mediaPlayer = null;
setPlayerState(STATE_End);

super.onDestroy();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
btnStart = (Button) rootView.findViewById(R.id.start);
btnPause = (Button) rootView.findViewById(R.id.pause);
btnStop = (Button) rootView.findViewById(R.id.stop);
btnSeek = (Button) rootView.findViewById(R.id.seekto);

btnStart.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.start();
setPlayerState(STATE_Started);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Play at Invalid state!",
Toast.LENGTH_LONG).show();
}
}
});

btnPause.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_Prepared //simulate a error case
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.pause();
setPlayerState(STATE_Paused);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Pause at Invalid state!",
Toast.LENGTH_LONG).show();
}
}
});

btnStop.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Stopped
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){

//Stop
mediaPlayer.stop();
setPlayerState(STATE_Stopped);

//then parepare in background thread
mediaPlayer.prepareAsync();
setPlayerState(STATE_Preparing);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Stop at Invalid state!",
Toast.LENGTH_LONG).show();
}

}
});

btnSeek.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.seekTo(0);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"SeekTo at Invalid state!",
Toast.LENGTH_LONG).show();
}
}});

textState = (TextView) rootView.findViewById(R.id.state);
textState.setText(getPlayerState());

textDuration = (TextView) rootView.findViewById(R.id.duration);
textPosition = (TextView) rootView.findViewById(R.id.position);
displayDurationPosition();

textDuration.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
displayDurationPosition();
}});

textPosition.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
displayDurationPosition();
}});

return rootView;
}

private void displayDurationPosition(){
textDuration.setText(
"Duration: " + mediaPlayer.getDuration() + " ms");
textPosition.setText(
"Current Position: " + mediaPlayer.getCurrentPosition() + " ms");
}

private void initMediaPlayer() {
Toast.makeText(getActivity(),
"initMediaPlayer()",
Toast.LENGTH_LONG).show();
mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);
setPlayerState(STATE_Prepared);

mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

@Override
public void onPrepared(MediaPlayer mp) {
setPlayerState(STATE_Prepared);
displayDurationPosition();
}});

mediaPlayer.setOnCompletionListener(new OnCompletionListener(){

@Override
public void onCompletion(MediaPlayer mp) {
setPlayerState(STATE_PlaybackCompleted);
displayDurationPosition();
}});

//Handle Error
mediaPlayer.setOnErrorListener(new OnErrorListener(){

@Override
public boolean onError(MediaPlayer mp, int what, int extra) {

setPlayerState(STATE_Error);

String errorWhat;
switch(what){
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
errorWhat = "MEDIA_ERROR_UNKNOWN";
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
errorWhat = "MEDIA_ERROR_SERVER_DIED";
break;
default:
errorWhat = "!";
}

String errorExtra;
switch(extra){
case MediaPlayer.MEDIA_ERROR_IO:
errorExtra = "MEDIA_ERROR_IO";
break;
case MediaPlayer.MEDIA_ERROR_MALFORMED:
errorExtra = "MEDIA_ERROR_MALFORMED";
break;
case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
errorExtra = "MEDIA_ERROR_UNSUPPORTED";
break;
case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
errorExtra = "MEDIA_ERROR_TIMED_OUT";
break;
default:
errorExtra = "!";
}

Toast.makeText(getActivity(),
"Error" + "\n"
+ errorWhat + "\n"
+ errorExtra,
Toast.LENGTH_LONG).show();

//release
mp.release();
initMediaPlayer();

return true;
}});
}

private void setPlayerState(int st){
stateMediaPlayer = st;

String stringState = getPlayerState();
if(textState!=null){
textState.setText(stringState);
}else{
Toast.makeText(getActivity(),
stringState, Toast.LENGTH_LONG).show();
}

}

private String getPlayerState(){
String strSt;
switch(stateMediaPlayer){
case STATE_Idle:
strSt = "Idle";
break;
case STATE_Initialized:
strSt = "Initialized";
break;
case STATE_Preparing:
strSt = "Preparing";
break;
case STATE_Prepared:
strSt = "Prepared";
break;
case STATE_Started:
strSt = "Started";
break;
case STATE_Paused:
strSt = "Paused";
break;
case STATE_Stopped:
strSt = "Stopped";
break;
case STATE_PlaybackCompleted:
strSt = "PlaybackCompleted";
break;
case STATE_End:
strSt = "End";
break;
case STATE_Error:
strSt = "Error";
break;
default:
strSt = "unknown...";
}
return strSt;
}
}

}


download filesDownload the files, without mp3.

Next:
Implement time bar for MediaPlayer, also introduce bug of MediaPlayer.seekTo()

Implement OnErrorListener for MP3 Player using MediaPlayer

The former post show how to Implement Android MP3 Player using MediaPlayer, without handle error case. To detect error for MediaPlayer, we can implement our OnErrorListener, and add it to MediaPlayer by calling setOnErrorListener().

Please note that this exercise show how to implement and add OnErrorListener, not how to solve the error.


To simpulate error in our exercise, modify the OnClickListener of btnPause, to accept if (stateMediaPlayer==STATE_Prepared), its a invalide case. When user click on the Pause button when the MediaPlayer is in STATE_Prepared, error will occur. Without OnErrorListener, OnCompletionListener will be called, many error message will be dispalyed in LogCat, and the MP3 cannot be play anymore.

Modify MainActivity.java in the former exercise to implement OnErrorListener. When error occur, release the old MediaPlay and instantiate a new one by calling initMediaPlayer().

package com.example.androidmp3player;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}

/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {

Button btnStart, btnPause, btnStop, btnSeek;
TextView textState, textDuration, textPosition;

MediaPlayer mediaPlayer;

private int stateMediaPlayer;
private final int STATE_Idle = 0;
private final int STATE_Initialized = 1;
private final int STATE_Preparing = 2;
private final int STATE_Prepared = 3;
private final int STATE_Started = 4;
private final int STATE_Paused = 5;
private final int STATE_Stopped = 6;
private final int STATE_PlaybackCompleted = 7;
private final int STATE_End = 8;
private final int STATE_Error = 9;

public PlaceholderFragment() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
initMediaPlayer();
}

@Override
public void onDestroy() {

Toast.makeText(getActivity(),
"release mediaPlayer",
Toast.LENGTH_LONG).show();
mediaPlayer.release();
mediaPlayer = null;
setPlayerState(STATE_End);

super.onDestroy();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
btnStart = (Button) rootView.findViewById(R.id.start);
btnPause = (Button) rootView.findViewById(R.id.pause);
btnStop = (Button) rootView.findViewById(R.id.stop);
btnSeek = (Button) rootView.findViewById(R.id.seekto);

btnStart.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.start();
setPlayerState(STATE_Started);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Play at Invalid state!",
Toast.LENGTH_LONG).show();
}
}
});

btnPause.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_Prepared //simulate a error case
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.pause();
setPlayerState(STATE_Paused);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Pause at Invalid state!",
Toast.LENGTH_LONG).show();
}
}
});

btnStop.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Stopped
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){

//Stop
mediaPlayer.stop();
setPlayerState(STATE_Stopped);

//then parepare in background thread
mediaPlayer.prepareAsync();
setPlayerState(STATE_Preparing);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Stop at Invalid state!",
Toast.LENGTH_LONG).show();
}

}
});

btnSeek.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.seekTo(0);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"SeekTo at Invalid state!",
Toast.LENGTH_LONG).show();
}
}});

mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

@Override
public void onPrepared(MediaPlayer mp) {
setPlayerState(STATE_Prepared);
displayDurationPosition();
}});

mediaPlayer.setOnCompletionListener(new OnCompletionListener(){

@Override
public void onCompletion(MediaPlayer mp) {
setPlayerState(STATE_PlaybackCompleted);
displayDurationPosition();
}});

//Handle Error
mediaPlayer.setOnErrorListener(new OnErrorListener(){

@Override
public boolean onError(MediaPlayer mp, int what, int extra) {

setPlayerState(STATE_Error);

String errorWhat;
switch(what){
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
errorWhat = "MEDIA_ERROR_UNKNOWN";
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
errorWhat = "MEDIA_ERROR_SERVER_DIED";
break;
default:
errorWhat = "!";
}

String errorExtra;
switch(extra){
case MediaPlayer.MEDIA_ERROR_IO:
errorExtra = "MEDIA_ERROR_IO";
break;
case MediaPlayer.MEDIA_ERROR_MALFORMED:
errorExtra = "MEDIA_ERROR_MALFORMED";
break;
case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
errorExtra = "MEDIA_ERROR_UNSUPPORTED";
break;
case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
errorExtra = "MEDIA_ERROR_TIMED_OUT";
break;
default:
errorExtra = "!";
}

Toast.makeText(getActivity(),
"Error" + "\n"
+ errorWhat + "\n"
+ errorExtra,
Toast.LENGTH_LONG).show();

//release
mp.release();
initMediaPlayer();

return true;
}});

textState = (TextView) rootView.findViewById(R.id.state);
textState.setText(getPlayerState());

textDuration = (TextView) rootView.findViewById(R.id.duration);
textPosition = (TextView) rootView.findViewById(R.id.position);
displayDurationPosition();

textDuration.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
displayDurationPosition();
}});

textPosition.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
displayDurationPosition();
}});

return rootView;
}

private void displayDurationPosition(){
textDuration.setText(
"Duration: " + mediaPlayer.getDuration() + " ms");
textPosition.setText(
"Current Position: " + mediaPlayer.getCurrentPosition() + " ms");
}

private void initMediaPlayer() {
Toast.makeText(getActivity(),
"initMediaPlayer()",
Toast.LENGTH_LONG).show();
mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);
setPlayerState(STATE_Prepared);
}

private void setPlayerState(int st){
stateMediaPlayer = st;

String stringState = getPlayerState();
if(textState!=null){
textState.setText(stringState);
}else{
Toast.makeText(getActivity(),
stringState, Toast.LENGTH_LONG).show();
}

}

private String getPlayerState(){
String strSt;
switch(stateMediaPlayer){
case STATE_Idle:
strSt = "Idle";
break;
case STATE_Initialized:
strSt = "Initialized";
break;
case STATE_Preparing:
strSt = "Preparing";
break;
case STATE_Prepared:
strSt = "Prepared";
break;
case STATE_Started:
strSt = "Started";
break;
case STATE_Paused:
strSt = "Paused";
break;
case STATE_Stopped:
strSt = "Stopped";
break;
case STATE_PlaybackCompleted:
strSt = "PlaybackCompleted";
break;
case STATE_End:
strSt = "End";
break;
case STATE_Error:
strSt = "Error";
break;
default:
strSt = "unknown...";
}
return strSt;
}
}

}


Keep using the layout files in last exercise.

download filesDownload the files, without mp3 file.

Remark: It's a BIG bug here, read next post: Re-set On..Listener after mediaPlayer.release and re-create MediaPlayer.

Implement Android MP3 Player using MediaPlayer

MediaPlayer class can be used to control playback of audio/video files and streams. It is a example to implement MP3 Player using MediaPlayer. Please note that you have to keep follow the State Diagram, otherwise IllegalStateException will be thrown.


Create a new Android Project in Eclipse, using the auto-generated code extend from ActionBarActivity.

The mp3 file is stored in /res/raw/vespers.mp3. Filename match with the following code in initMediaPlayer().

mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);

MainActivity.java
package com.example.androidmp3player;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}

/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {

Button btnStart, btnPause, btnStop, btnSeek;
TextView textState, textDuration, textPosition;

MediaPlayer mediaPlayer;

private int stateMediaPlayer;
private final int STATE_Idle = 0;
private final int STATE_Initialized = 1;
private final int STATE_Preparing = 2;
private final int STATE_Prepared = 3;
private final int STATE_Started = 4;
private final int STATE_Paused = 5;
private final int STATE_Stopped = 6;
private final int STATE_PlaybackCompleted = 7;
private final int STATE_End = 8;
private final int STATE_Error = 9;

public PlaceholderFragment() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
initMediaPlayer();
}

@Override
public void onDestroy() {

Toast.makeText(getActivity(),
"release mediaPlayer",
Toast.LENGTH_LONG).show();
mediaPlayer.release();
mediaPlayer = null;
setPlayerState(STATE_End);

super.onDestroy();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
btnStart = (Button) rootView.findViewById(R.id.start);
btnPause = (Button) rootView.findViewById(R.id.pause);
btnStop = (Button) rootView.findViewById(R.id.stop);
btnSeek = (Button) rootView.findViewById(R.id.seekto);

btnStart.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.start();
setPlayerState(STATE_Started);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Play at Invalid state!",
Toast.LENGTH_LONG).show();
}
}
});

btnPause.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.pause();
setPlayerState(STATE_Paused);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Pause at Invalid state!",
Toast.LENGTH_LONG).show();
}
}
});

btnStop.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Stopped
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){

//Stop
mediaPlayer.stop();
setPlayerState(STATE_Stopped);

//then parepare in background thread
mediaPlayer.prepareAsync();
setPlayerState(STATE_Preparing);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"Stop at Invalid state!",
Toast.LENGTH_LONG).show();
}

}
});

btnSeek.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
if(stateMediaPlayer==STATE_Prepared
|| stateMediaPlayer==STATE_Started
|| stateMediaPlayer==STATE_Paused
|| stateMediaPlayer==STATE_PlaybackCompleted){
mediaPlayer.seekTo(0);

displayDurationPosition();
}else{
Toast.makeText(getActivity(),
"SeekTo at Invalid state!",
Toast.LENGTH_LONG).show();
}
}});

mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

@Override
public void onPrepared(MediaPlayer mp) {
setPlayerState(STATE_Prepared);
displayDurationPosition();
}});

mediaPlayer.setOnCompletionListener(new OnCompletionListener(){

@Override
public void onCompletion(MediaPlayer mp) {
setPlayerState(STATE_PlaybackCompleted);
displayDurationPosition();
}});

textState = (TextView) rootView.findViewById(R.id.state);
textState.setText(getPlayerState());

textDuration = (TextView) rootView.findViewById(R.id.duration);
textPosition = (TextView) rootView.findViewById(R.id.position);
displayDurationPosition();

textDuration.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
displayDurationPosition();
}});

textPosition.setOnClickListener(new OnClickListener(){

@Override
public void onClick(View v) {
displayDurationPosition();
}});

return rootView;
}

private void displayDurationPosition(){
textDuration.setText(
"Duration: " + mediaPlayer.getDuration() + " ms");
textPosition.setText(
"Current Position: " + mediaPlayer.getCurrentPosition() + " ms");
}

private void initMediaPlayer() {
Toast.makeText(getActivity(),
"initMediaPlayer()",
Toast.LENGTH_LONG).show();
mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);
setPlayerState(STATE_Prepared);
}

private void setPlayerState(int st){
stateMediaPlayer = st;

String stringState = getPlayerState();
if(textState!=null){
textState.setText(stringState);
}else{
Toast.makeText(getActivity(),
stringState, Toast.LENGTH_LONG).show();
}

}

private String getPlayerState(){
String strSt;
switch(stateMediaPlayer){
case STATE_Idle:
strSt = "Idle";
break;
case STATE_Initialized:
strSt = "Initialized";
break;
case STATE_Preparing:
strSt = "Preparing";
break;
case STATE_Prepared:
strSt = "Prepared";
break;
case STATE_Started:
strSt = "Started";
break;
case STATE_Paused:
strSt = "Paused";
break;
case STATE_Stopped:
strSt = "Stopped";
break;
case STATE_PlaybackCompleted:
strSt = "PlaybackCompleted";
break;
case STATE_End:
strSt = "End";
break;
case STATE_Error:
strSt = "Error";
break;
default:
strSt = "unknown...";
}
return strSt;
}
}

}

fragment_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.example.androidmp3player.MainActivity$PlaceholderFragment" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://arteluzevida.blogspot.com/"
android:textStyle="bold" />

<Button
android:id="@+id/start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start" />
<Button
android:id="@+id/pause"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pause" />
<Button
android:id="@+id/stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Stop" />
<Button
android:id="@+id/seekto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Seek To Beginning" />
<TextView
android:id="@+id/state"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/duration"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/position"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</LinearLayout>

Auto generated activity_main.xml.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.androidmp3player.MainActivity"
tools:ignore="MergeRootFrame" />


download filesDownload the files (not include the mp3 file).

Next:
Implement OnErrorListener.
Re-set On..Listener after mediaPlayer.release and re-create MediaPlayer
Implement time bar for MediaPlayer, also introduce bug of MediaPlayer.seekTo()