无法让Android MediaPlayer onCompletion触发
我想使用Android MediaPlayer类播放一些声音。无法让Android MediaPlayer onCompletion触发
下面是此代码在服务运行的代码
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();
,但由于某些原因,播放声音好,但任何事情放到onCompletion似乎不火。然后,我在logcat中收到消息,说明mediaplayer没有发布。我对此感到不知所措。
我在galaxy nexus 4.0.4 stock ROM上运行这个测试。
我还注意到声音最后可能会被截断。
这是我如何把它:
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();
}
这其实很简单(但愚蠢的)。你调用启动(在设置你的听众),像这样:
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();
}
});
你能解释为什么在设置完成监听器之前调用start()很重要吗?这是Android的怪癖吗? – 2015-06-02 04:58:23
@FabianTamp这是另一个Android怪癖。它可能不是所有设备都需要的(或者甚至不再需要),但当时它绝对是解决问题的方法。 – ajacian81 2015-06-03 15:30:22
虽然我看不到任何证据支持为什么会修复Android源代码中的内容。对我来说,根本问题是MediaPlayer在播放前已经GC'd,我已经添加了一个更详细的答案:) – 2015-06-04 01:04:12
我遇到类似的症状此,根本原因是,MediaPlayer
居然也得到了OnCompletionListener
之前收集的垃圾是被调用。
从你的代码判断,它看起来像是同样的问题 - 你的代码没有对MediaPlayer进行长时间的引用,所以一旦该函数结束(并且在音频结束播放之前),MediaPlayer就会变得易受影响到GC。
此问题是由该日志线上可识别:
02-22 13:14:57.969: W/MediaPlayer-JNI(16888): MediaPlayer finalized without being released
您可以通过重新构建该类使得MediaPlayer
参考保持更长的时间解决这个问题 - 通过存储在活动对它的引用和重用例如,同一个实例可以多次播放相同的声音。
这里有一个更详细的解释:Garbage Collection causes : MediaPlayer finalized without being released
有初始化的MediaPlayer对象两种方法,“新”和“创建()”。为了执行OnCompletionListener,它在这两种方法中获得的对象是不同的。
1)中的 “新” 办法
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) “创造” 的方法
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();
}
});
对于create()方法,我都经历过类似的问题。如果在调用create()之后调用mp.prepare(),则该过程永远不会到达以下setOnCompletionListener,甚至不会到达start()。基本原因是“对象处于准备状态,如果使用create方法创建成功”(https://developer.android.com/reference/android/media/MediaPlayer.html)。所以你不需要在使用create()方法后调用prepare()。
其实,原因是MediaPlayer是一个局部变量。该功能完成后,MediaPlayer将由GC收集。 所以修复很简单,让您的MediaPlayer成为该课程的一员。
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();
}
}
我猜“视频”是MediaPlayer的一个实例吗?并且你的课堂上有一个“实现MediaPlayer.OnCompletionListener”?我也试过这种方法,但它没有奏效。 – Andrew 2012-04-04 06:06:34
@Andrew它如何被接受的答案,如果它没有工作?你做到了吗?如果是,如何? – hendrix 2013-04-04 15:40:06
@smitalm在设置侦听器之前调用start()。 – ajacian81 2013-10-24 01:50:41