Не удается заставить 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();
    }
}