2012-04-03 20 views
11

Estoy tratando de usar la clase android MediaPlayer para reproducir algunos sonidos.No se puede obtener Android MediaPlayer onCompletion para disparar

Aquí está el código

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(); 

Este código se ejecuta en un servicio, pero por alguna razón el sonido se reproduce bien, pero nada se coloca en la onCompletion no parece al fuego. Luego recibo un mensaje en el logcat que dice que el reproductor multimedia no fue lanzado. No entiendo por qué me equivoqué con esto.

Estoy ejecutando esta prueba en una galaxia nexus 4.0.4 stock rom.

También observo que el sonido puede cortarse al final.

Respuesta

3

Aquí es cómo lo tengo:

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();  
} 
+0

Supongo que "video" es una instancia de MediaPlayer? y que tienes un "implemento MediaPlayer.OnCompletionListener" en tu clase? He intentado este método también pero no funcionó. – Andrew

+2

@Andrew ¿Cómo se acepta la respuesta, si no funcionó? ¿Lo hiciste funcionar? Si es así, ¿cómo? – hendrix

+2

@smitalm call start() antes de configurar su oyente. – ajacian81

26

En realidad es sencillo (pero tonta). Establecer su oyente después de llamar a start(), así:

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

¿Podría explicar por qué llamar a start() antes de configurar el oyente de finalización es importante? ¿Es un capricho de Android? –

+0

@FabianTamp es otra peculiaridad de Android. Puede que no sea necesario para todos los dispositivos (o incluso más), pero en el momento definitivamente fue una solución para el problema. – ajacian81

+1

No pude ver ninguna evidencia que respalde por qué eso arreglaría las cosas en la fuente de Android. Resulta que el problema de raíz para mí fue que el MediaPlayer estaba siendo GC antes de que terminara de reproducirse, he agregado una respuesta que describe con más detalle :) –

1

me estaba encontrando síntomas similares a esta, y la causa fue que el MediaPlayer estaba recibiendo basura recogida antes de la OnCompletionListener estaba siendo llamado.

A juzgar por su código, parece el mismo problema: su código no contiene una referencia duradera del MediaPlayer, por lo que tan pronto como termine esa función (y antes de que el audio termine de reproducirse) el MediaPlayer es susceptible a GC.

Este problema se puede identificar mediante esta línea de registro:

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

se puede arreglar por rediseñar la clase de tal manera que la referencia MediaPlayer se mantiene durante más tiempo - al almacenar una referencia a él en la actividad, y la reutilización la misma instancia para reproducir el mismo sonido varias veces, por ejemplo.

Hay una explicación más detallada aquí: Garbage Collection causes : MediaPlayer finalized without being released

0

Hay dos enfoques para inicializar el objeto MediaPlayer, "nuevo" y "Create()". Para hacer OnCompletionListener, es diferente para los objetos obtenidos en estos dos enfoques.

1) el "nuevo" enfoque

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) el método de "crear"

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(); 
    } 
}); 

Para el método de crear(), que han experimentado el problema similar. Si se llama a mp.prepare() después de llamar a create(), el procedimiento nunca alcanzará el siguiente setOnCompletionListener, ni siquiera al inicio(). La razón esencial es que "los objetos están en el estado Preparado si la creación mediante el método create es exitosa" (https://developer.android.com/reference/android/media/MediaPlayer.html). Por lo tanto, no necesita llamar a prepare() después de usar el método create().

0

En realidad, la razón es que el MediaPlayer es una variable local. Una vez que la función finaliza, GC recopila el MediaPlayer. Así que la solución es fácil, haga que su MediaPlayer sea miembro de la clase.

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(); 
    } 
} 
Cuestiones relacionadas