Question

After two weeks of trying to fix issues with my media player code continue to have users report crashes, I am at my wits end trying to see what I am doing wrong.

Media player and background sound objects initialized in main class:

public class GameOver extends Activity{

public AdView adView;
BackgroundSound mBackgroundSound;
MediaPlayer mMediaPlayer;

Here is my media player code and methods associated with it, I dont call anything in on back pressed:

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

    protected void onPreExecute() {
        mMediaPlayer = MediaPlayer.create(GameOver.this, R.raw.welldone);
    }

    protected Void doInBackground(Void... params) {
        mMediaPlayer.setVolume(100, 100);
        mMediaPlayer.start();
        mMediaPlayer.setLooping(true); // Set looping
        return null;
    }

    protected void onCancelled(Void v) {
        try {
            mMediaPlayer.stop();
            mMediaPlayer.reset();
            mMediaPlayer.release();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

}

public void onPause() {
    super.onPause();
    mBackgroundSound.onCancelled((Void) null);
}

public void onResume() {
    super.onResume();
    mBackgroundSound = new BackgroundSound();
    mBackgroundSound.execute((Void) null);

}

Here are a few of the example crashes:

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:200)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
at java.lang.Thread.run(Thread.java:1019)
Caused by: java.lang.IllegalStateException
at android.media.MediaPlayer.setVolume(Native Method)
at com.deucalion0.findtheanimal.Menu$BackgroundSound.doInBackground(Menu.java:235)
at com.deucalion0.findtheanimal.Menu$BackgroundSound.doInBackground(Menu.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:185)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
... 4 more

And another:

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:299)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
Caused by: java.lang.IllegalStateException
at android.media.MediaPlayer.setLooping(Native Method)
at com.deucalion0.findtheanimal.Menu$BackgroundSound.doInBackground(Menu.java:234)
at com.deucalion0.findtheanimal.Menu$BackgroundSound.doInBackground(Menu.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
... 5 more

I have read many Stackoverflow questions, tried to make sense of the Google documentation and everything I have tried seems to be a bad solution. I do not know how to proceed, can someone please advise?

Was it helpful?

Solution

Why are you using the AsyncTask in this way?

What it does now:

  • Creates the MediaPlayer on the main thread - it's a long process, so it should go to the background thread, it can cause ANRs.
  • Calls setVolume, start, setLooping from background thread - these are very short commands, so no need to run them in the background.
  • Calls stop, reset and release from the main thread.

What would be a working solution:

  • Create your MediaPlayer from the background thread.
  • After created, set looping and start playing. (These are fast calls, so you can do it from main thread if you prefer it, but only after your MediaPlayer has been created.)
  • When you want to stop play (in your example, when onPause called), you can call stop() and release(). But check before, if it has been created and started (because it is done in the background thread, it is possible, that you pause your activity before mediaplayer starts playing the audio).

EDIT: this is the source code I tested, it works for me (even if the preparing time for the media player is really slow, and the activity is paused before it loads):

private MediaPlayer mMediaPlayer;
private volatile boolean mMediaPlayerStopped ;

@Override
protected void onPause() {
    Log.v("MusicTest", "Paused activity") ;
    stopMediaPlayer();
    super.onPause();
}

private void stopMediaPlayer() {
    Log.v("MusicTest", "Stopping MediaPlayer") ;
    mMediaPlayerStopped = true ;
    if (mMediaPlayer != null) {
        mMediaPlayer.stop() ;
        mMediaPlayer.reset() ;
        mMediaPlayer.release() ;
        mMediaPlayer = null ;
    }
}

private void startMediaPlayer() {
    mMediaPlayerStopped = false ;
    new AsyncTask<Void, Void, Void>() {

        @Override
        protected Void doInBackground(Void... params) {
            Log.v("MusicTest", "Creating MediaPlayer") ;
            MediaPlayer mediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.alarm10);
            mediaPlayer.setVolume(100, 100) ;
            mediaPlayer.setLooping(true) ;
            Log.v("MusicTest", "Starting MediaPlayer") ;
            mediaPlayer.start() ;
            mMediaPlayer = mediaPlayer ;
            if (mMediaPlayerStopped) {
                Log.v("MusicTest", "MediaPlayer was stopped while preparing") ;
                stopMediaPlayer();
            }
            return null;
        }
    }.execute();
}

@Override
protected void onResume() {
    Log.v("MusicTest", "Resumed activity") ;
    startMediaPlayer();
    super.onResume();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top