This code works so far on devices I have tested, (ALL mdpi level devices).
private void stopSounds() {
if (mp!=null && mp.isPlaying()) {
mp.stop();
mp.reset();
mp.release();
mp = null;
}
}
private void playSounds(int sound) {
stopSounds();
mp = new MediaPlayer();
mp = MediaPlayer.create(this, sound);
mp.start();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
playSounds(R.raw.correct_amazing);
break;
case R.id.button2:
playSounds(R.raw.correct_awesome);
break;
case R.id.button3:
playSounds(R.raw.correct_chick);
break;
default:
break;
}
}
No errors or exceptions so far, I considered releasing the MediaPlayer object(mp) after it has completed (playing).
So I just tried adding onCompletionListener as follows, in playSounds() :
private void playSounds(int sound) {
stopSounds();
mp = new MediaPlayer();
mp = MediaPlayer.create(this, sound);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mep) {
mep.stop();
mep.reset();
mep.release();
mep = null;
}
});
}
Then it started throwing "IllegalStateException" as follows,
01-22 17:51:24.150: W/dalvikvm(3081): threadid=1: thread exiting with uncaught exception (group=0x41e2e498)
01-22 17:51:24.150: E/test(3081): Exception
01-22 17:51:24.180: E/AndroidRuntime(3081): FATAL EXCEPTION: main
01-22 17:51:24.180: E/AndroidRuntime(3081): java.lang.IllegalStateException
01-22 17:51:24.180: E/AndroidRuntime(3081): at android.media.MediaPlayer.isPlaying(Native Method)
01-22 17:51:24.180: E/AndroidRuntime(3081): at com.Test.mediaplayertert.MPActivity.stopSounds(MPActivity.java:30)
01-22 17:51:24.180: E/AndroidRuntime(3081): at com.Test.mediaplayertert.MPActivity.playSounds(MPActivity.java:39)
01-22 17:51:24.180: E/AndroidRuntime(3081): at com.Test.mediaplayertert.MPActivity.onClick(MPActivity.java:61)
01-22 17:51:24.180: E/AndroidRuntime(3081): at android.view.View.performClick(View.java:4106)
01-22 17:51:24.180: E/AndroidRuntime(3081): at android.view.View$PerformClick.run(View.java:17150)
01-22 17:51:24.180: E/AndroidRuntime(3081): at android.os.Handler.handleCallback(Handler.java:615)
01-22 17:51:24.180: E/AndroidRuntime(3081): at android.os.Handler.dispatchMessage(Handler.java:92)
01-22 17:51:24.180: E/AndroidRuntime(3081): at android.os.Looper.loop(Looper.java:137)
01-22 17:51:24.180: E/AndroidRuntime(3081): at android.app.ActivityThread.main(ActivityThread.java:4793)
01-22 17:51:24.180: E/AndroidRuntime(3081): at java.lang.reflect.Method.invokeNative(Native Method)
01-22 17:51:24.180: E/AndroidRuntime(3081): at java.lang.reflect.Method.invoke(Method.java:511)
01-22 17:51:24.180: E/AndroidRuntime(3081): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:808)
01-22 17:51:24.180: E/AndroidRuntime(3081): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:575)
01-22 17:51:24.180: E/AndroidRuntime(3081): at dalvik.system.NativeStart.main(Native Method)
My problem is I have some 6 buttons on screen and user presses them as long as they are on the activity and I need to play "correct" sounds, "wrong" sounds respectively. So, it will take continuous pressings.
My above error is occuring after mp object is released via setOnCompletionListener().
I want to know how to efficiently handle mediaplayer in the above mentioned conditions (Or) How to Release mediaplayer object after it has completed playing?
Your exception happens when you click a button AFTER a previous sound has been stopped in OnCompletionListener(). It's a subtle error, so easy to miss. Here's what's happening:
You click a button, and playSounds() is called, where your global MediaPlayer object is initialised, and an OnCompletionListener is set.
Inside OnCompletionListener() you try to release the player that fired onCompletion
Now, Java is pass-by-value. What it means is that here:
@Override
public void onCompletion(MediaPlayer mep)
mep is a reference to your global mp object, so you can do operations, such as stop(), reset() etc., but when you do:
mep = null;
you're null'nig - as I understand - that reference (which is a value), NOT the global object.
So assuming that the sound finished (OnCompletionListener was called), and you click another button, playSounds() gets called, which calls stopSounds(), where you're checking:
if (mp != null ... <-------- here, mp will NOT be null
and in the same line you're checking
mp.isPlaying()) { <----------- THIS IS CAUSING AN EXCEPTION
Why? Remember, in OnCompletionListener, you called reset() and release(), which puts the state of MediaPlayer into idle and end state respectively, and as the docs say, an exception will be thrown if isPlaying() is called in the wrong
state:
IllegalStateException - if the internal player engine has not been initialized or has been released
SOLUTION:
Slightly modify your OnCompletionListener, so that it nulls your global MediaPlayer object:
@Override
public void onCompletion(MediaPlayer mep) {
mep.stop();
mep.reset();
mep.release();
//null the global MediaPlayer object
mp = null;
}
Here are some excellent articles about Java being pass-by-value, where it's explained much better than my attempt :)
Is Java "pass-by-reference" or "pass-by-value"?
http://javadude.com/articles/passbyvalue.htm