Reputation: 1747
Im streaming an mp3 audio from a url by using mediaplayer, Now im able to play music , But when i press back button or close the app, it crashes. can anyone pls help me to find my mistake. thank you.
My code is :
private ImageView play, forward, backward;
private MediaPlayer mediaPlayer;
private boolean playing = false;
private ProgressDialog dialog;
private String mp3link;
private SeekBar seekbar;
private Handler handler = new Handler();
private int mediaPos;
private int mediaMax;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String url ="";
initWidgets();
}
private void initWidgets() {
mp3link = "http://loc8app.com/church/uploads/audio/749928ad6fcb7b1aceefdf03bd7a9465.mp3";
play = (ImageView) findViewById(R.id.control);
seekbar = (SeekBar) findViewById(R.id.seekBar);
// forward = (ImageView) findViewById(R.id.playeer_forward);
// backward = (ImageView) findViewById(R.id.playeer_back);
mediaPlayer = new MediaPlayer();
play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
playFunction();
}
});
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(mediaPlayer != null && fromUser){
mediaPlayer.seekTo(progress);
}
}
});
}
private void playFunction() {
if (!playing) {
try {
dialog = ProgressDialog
.show(MainActivity.this,
"",
getString(com.root5solutions.music.R.string.buffering),
true);
dialog.setCancelable(true);
dialog.show();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(mp3link);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
play.setBackgroundResource(R.drawable.pause);
playing = true;
//this is new
mediaPos = mp.getCurrentPosition();
mediaMax = mp.getDuration();
seekbar.setMax(mediaMax);
seekbar.setProgress(mediaPos);
//this line is the error
handler.removeCallbacks(moveSeekBarThread);
handler.postDelayed(moveSeekBarThread, 100);
mp.start();
dialog.dismiss();
}
});
mediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
dialog.dismiss();
}
} else {
play.setBackgroundResource(R.drawable.play);
mediaPlayer.stop();
mediaPlayer.release();
playing = false;
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
private Runnable moveSeekBarThread = new Runnable() {
public void run() {
if (mediaPlayer.isPlaying()) {
int mediaPos_new = mediaPlayer.getCurrentPosition();
int mediaMax_new = mediaPlayer.getDuration();
seekbar.setMax(mediaMax_new);
seekbar.setProgress(mediaPos_new);
handler.postDelayed(this, 1000); // Looping the thread after 1 second
}
}
};
}
Logcat shows :
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.root.music, PID: 26981
java.lang.IllegalStateException
at android.media.MediaPlayer.isPlaying(Native Method)
at com.root.music.MainActivity$4.run(MainActivity.java:132)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5351)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:947)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:742)
Upvotes: 1
Views: 1001
Reputation: 123
First you need to understand what illegalStateException means:
According to Android docs:
It Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
have a look at the state diagram of a media player:
https://developer.android.com/images/mediaplayer_state_diagram.gif
Calling setDataSource(FileDescriptor), or setDataSource(String), or setDataSource(Context, Uri), or setDataSource(FileDescriptor, long, long), or setDataSource(MediaDataSource) transfers a MediaPlayer object in the Idle state to the Initialized state. An IllegalStateException is thrown if setDataSource() is called in any other state.
It is good programming practice to always look out for IllegalArgumentException and IOException that may be thrown from the overloaded setDataSource methods.
Upvotes: 0
Reputation: 1133
The issue appears to be being caused by the moveSeekBarThread
Runnable
, from which the exception is being raised, continuing to execute after mediaPlayer
is released in onBackPressed()
. This results in the the isPlaying()
method being executed, which as per the documentation will result in an IllegalStateException
:
if the internal player engine has not been initialized or has been released.
Looking at moveSeekBarThread
, it seems to be configured to reschedule itself endlessly by posting itself back into the handler
Handler
instance with a delay. This process is not being stopped when the user leaves the activity, which explains why moveSeekBarThread
keeps running. So, based on the above, one solution could be to make sure that any instances of moveSeekBarThread
in handler
's queue are removed before calling mediaPlayer.release()
when the user leaves the activity.
You should be able to do that by calling handler.removeCallbacks(moveSeekBarThread);
before you call mediaPlayer.release()
. For example, as follows:
@Override
public void onBackPressed() {
super.onBackPressed();
handler.removeCallbacks(moveSeekBarThread);
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
It should be okay to call it right before mediaPlayer.release()
, but I think it's safer to call it regardless of whether mediaPlayer
is playing. This way, if the Runnable
does get or remain started somehow despite the media player not having being started or having been stopped, the Runnable
will still be cleared.
As an aside, while I don't have any experience with MediaPlayer
, I happened to notice that the documentation of the release
method has the following to say:
It is considered good practice to call this method when you're done using the MediaPlayer. In particular, whenever an Activity of an application is paused (its onPause() method is called), or stopped (its onStop() method is called), this method should be invoked to release the MediaPlayer object, unless the application has a special need to keep the object around. In addition to unnecessary resources (such as memory and instances of codecs) being held, failure to call this method immediately if a MediaPlayer object is no longer needed may also lead to continuous battery consumption for mobile devices, and playback failure for other applications if no multiple instances of the same codec are supported on a device.
So unless there is that special need to keep the media player around in the activity in your case, it might be better to handle the release process (including clearing moveSeekBarThread
from handler
) in onPause
or onStop
instead.
Hope that helps!
Upvotes: 1
Reputation: 75798
you are getting IllegalStateException .
Signals that a method has been invoked at an illegal or inappropriate time .
Call super.onBackPressed();
after if condition
@Override
public void onBackPressed()
{
if (mediaPlayer!= null)
{
if(mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
}
super.onBackPressed(); // Call here
}
Upvotes: 1