Cannot get android MediaPlayer onCompletion to fire

橙三吉。 提交于 2019-12-10 01:06:33

问题


I'm trying to use the android MediaPlayer class to play some sounds.

Here's the code

MediaPlayer mp = new MediaPlayer(); 
mp.setDataSource(context, Uri.parse(soundUrl)); 
mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
mp.setLooping(false); 
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
    @Override 
            public void onCompletion(MediaPlayer mp) { 
                Log.i(LOGTAG, "onComplete hit"); 
                mp.stop(); 
                mp.release(); 
            } 
    });         

mp.prepare(); 
mp.start();

This code runs in a service, but for some reason the sound plays ok, but anything placed into the onCompletion doesn't seem to fire. I then get a message in the logcat that the mediaplayer wasn't released. I'm at a loss to what I've got wrong with this.

I'm running this testing on a galaxy nexus 4.0.4 stock rom.

I also notice that the sound can get clipped at the end.


回答1:


Here is how I have it:

    video.setOnCompletionListener(this);
    IntroClip.execute(video);
}

@Override
public void onCompletion(MediaPlayer mp){
    Button LoginButton;
    Button CreateAccount;
    Button RecoverPass;

    setContentView(R.layout.loginmenu);
    Spin = (ProgressBar)findViewById(R.id.Spinner);

    mp.release();       
}



回答2:


It's actually simple (but silly). Set your listener after you call start(), like so:

ediaPlayer mp = new MediaPlayer(); 
mp.setDataSource(context, Uri.parse(soundUrl)); 
mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
mp.setLooping(false); 
mp.prepare(); 
mp.start();
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
    @Override 
            public void onCompletion(MediaPlayer mp) { 
                Log.i(LOGTAG, "onComplete hit"); 
                mp.stop(); 
                mp.release(); 
            } 
    });         



回答3:


I was encountering similar symptoms to this, and the root cause was that the MediaPlayer was getting garbage collected before the OnCompletionListener was being called.

Judging from your code, it looks like the same problem - your code doesn't hold a long-lived reference to the MediaPlayer, so as soon as that function ends (and before the audio finishes playing) the MediaPlayer is susceptible to GC.

This problem is identifiable by this log line:

02-22 13:14:57.969: W/MediaPlayer-JNI(16888): MediaPlayer finalized without being released

You can fix it by rearchitecting the class such that the MediaPlayer reference is kept for longer - by storing a reference to it in the activity, and reusing the same instance to play the same sound multiple times, for example.

There's a more detailed explanation here: Garbage Collection causes : MediaPlayer finalized without being released




回答4:


There are two approaches to initialise the MediaPlayer object, "new" and "create()". In order to do OnCompletionListener, it is different for the objects obtained in these two approaches.

1) the "new" approach

MediaPlayer mp = new MediaPlayer();
mp.setDataSource(context, Uri.parse(soundUrl)); 
mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
mp.setLooping(false); 
mp.prepare(); 
mp.start();
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
    @Override 
    public void onCompletion(MediaPlayer mp) { 
        Log.i(LOGTAG, "onComplete hit"); 
        mp.stop(); 
        mp.release(); 
    } 
}); 

2) the "create" method

MediaPlayer mp = MediaPlayer.create(getActivity(), Uri.parse(soundUrl));
//mp.prepare() is not needed here
mp.setLooping(false);
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
    @Override
    public void onCompletion(MediaPlayer mp) {
        Log.i(LOGTAG, "onComplete hit");
        mp.stop();
        mp.release();
    }
});

For the create() method, I have experienced the similar issue. If mp.prepare() is called after calling the create(), the procedure will never reach the following setOnCompletionListener, not even to the start(). The essential reason is that "the objects are in the Prepared state if the creation using create method is successful"(https://developer.android.com/reference/android/media/MediaPlayer.html). So you do not need to call the prepare() after using the create() method.




回答5:


Actually, the reason is that the MediaPlayer is a local variable. After the function is finished, the MediaPlayer is collected by GC. So the fix is easy, make your MediaPlayer a member of the class.

YourClassName {
    MediaPlayer mp = new MediaPlayer(); 

    void YourFunction() {
          mp.setDataSource(context, Uri.parse(soundUrl)); 
          mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
          mp.setLooping(false); 
          mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
              @Override 
              public void onCompletion(MediaPlayer mp) { 
                  Log.i(LOGTAG, "onComplete hit"); 
                  mp.stop(); 
                  mp.release(); 
              }
          });         
          mp.prepare(); 
          mp.start();
    }
}


来源:https://stackoverflow.com/questions/9998677/cannot-get-android-mediaplayer-oncompletion-to-fire

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!