Не удается заставить android MediaPlayer onCompletion загореться
Я пытаюсь использовать класс android MediaPlayer для воспроизведения некоторых звуков.
Здесь код
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, что медиаплеер не был выпущен. Я в недоумении, что у меня с этим не получается.
Я выполняю это тестирование на галактике nexus 4.0.4.
Я также замечаю, что звук может быть сжат в конце.
Ответы
Ответ 1
Вот как это у меня:
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
Это на самом деле просто (но глупо). Установите своего слушателя после вызова start(), например:
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
Я столкнулся с подобными симптомами, и основная причина заключалась в том, что MediaPlayer
собирал мусор перед тем, как вызывался OnCompletionListener
.
Судя по вашему коду, это похоже на ту же проблему - ваш код не содержит долговечную ссылку на MediaPlayer, поэтому, как только эта функция закончится (и до того, как звук закончит воспроизведение), MediaPlayer восприимчив к ГХ.
Эта проблема идентифицируется по этой строке журнала:
02-22 13:14:57.969: W/MediaPlayer-JNI(16888): MediaPlayer finalized without being released
Вы можете исправить это, перестроив таким образом класс, чтобы ссылка MediaPlayer
хранилась дольше - путем хранения ссылки на нее в действии и повторного использования одного и того же экземпляра для воспроизведения одного и того же звука несколько раз, например.
Здесь есть более подробное объяснение: Причины сбора мусора: MediaPlayer завершен без выпуска
Ответ 4
Существует два подхода к инициализации объекта MediaPlayer: "new" и "create()". Чтобы сделать 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) метод "create"
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() у меня возникла аналогичная проблема. Если mp.prepare() вызывается после вызова create(), процедура никогда не достигнет следующего setOnCompletionListener, даже не для начала(). Существенная причина заключается в том, что " объекты находятся в состоянии" Готово ", если создание с использованием метода создания выполнено успешно" (https://developer.android.com/reference/android/media/MediaPlayer.html). Поэтому вам не нужно вызывать метод prepare() после использования метода create().
Ответ 5
Собственно, причина в том, что 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();
}
}