¿Cómo hacer que WakefulService (IntentService) espere hasta que MediaPlayer termine?

Estoy tratando de hacer una aplicación, que reproduce series de sonidos utilizando MediaPlayer, a horas programadas. Para manejar correctamente el bloqueo de la vigilia y programar la reproducción, utilicé WakefulIntentService de CommonsWare .

Desafortunadamente, el hilo de trabajo de IntentService se cierra inmediatamente después de llamar a MediaPlayer.play() y no se llama a los oyentes registrados de MediaPlayer. En su lugar, se registra la excepción:

 W/MessageQueue(6727): Handler (android.media.MediaPlayer$EventHandler) {4160d820} sending message to a Handler on a dead thread W/MessageQueue(6727): java.lang.RuntimeException: Handler (android.media.MediaPlayer$EventHandler) {4160d820} sending message to a Handler on a dead thread W/MessageQueue(6727): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:294) W/MessageQueue(6727): at android.os.Handler.sendMessageAtTime(Handler.java:473) W/MessageQueue(6727): at android.os.Handler.sendMessageDelayed(Handler.java:446) W/MessageQueue(6727): at android.os.Handler.sendMessage(Handler.java:383) W/MessageQueue(6727): at android.media.MediaPlayer.postEventFromNative(MediaPlayer.java:2063) W/MessageQueue(6727): at dalvik.system.NativeStart.run(Native Method) 

Por lo que entiendo, es causado por el hilo de trabajo ya está muerto cuando MediaPlayer completa. Si hago una pausa en el hilo por medio del depurador y dejo que el reproductor termine, todo funciona bien.

En mis oyentes no solo publico los recursos de MediaPlayer, sino que uso OnCompletionListener para hacer llamadas MediaPlayer.play() consecutivas hasta que la cola de sonido esté vacía.

Intenté poner un lazo de la espera inmediatamente después de la llamada del play() inicial play() , comprobando para una bandera de finalización de encargo, pero parece congelar porque callbacks de MediaPlayer se llaman en el mismo play() hilo play() fue llamado.

La pregunta es, ¿cómo puedo hacer que el hilo de trabajo no salga antes de dejarlo hacerlo (es decir, el ha sido procesado y el método onCompletion() se ha llamado por última vez?

Aquí está el código de mi servicio:

 public class SoundService extends WakefulIntentService { private static final TAG = "SoundService"; private final Queue<SoundDescriptor> soundQueue = new ConcurrentLinkedQueue<SoundDescriptor>(); private final OnCompletionListener onComediaPlayerletionListener = new OnComediaPlayerletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { mediaPlayer.reset(); try { if (!playNextFromQueue(mediaPlayer)) { Log.v(TAG, "Reached end of queue. Cleaning up."); release(); } } catch (Exception e) { Log.e(TAG, "Exception!", e) release(); } } }; private final OnErrorListener onErrorListener = new OnErrorListener() { @Override public boolean onError(MediaPlayer mediaPlayer, int what, int extra) { Log.v(TAG, "Error!!"); release(); return false; } }; public SoundService() { // populate soundQueue } protected void doWakefulWork(Intent intent) { MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setOnComediaPlayerletionListener(onComediaPlayerletionListener); mediaPlayer.setOnErrorListener(onErrorListener); playNextFromQueue(mediaPlayer); } private boolean playNextFromQueue(MediaPlayer mediaPlayer) throws IllegalArgumentException, IllegalStateException, IOException { SoundDescriptor descriptor = soundQueue.poll(); if (descriptor != null) { mediaPlayer.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength()); descriptor.close(); mediaPlayer.prepare(); mediaPlayer.start(); return true; } else { return false; } } } 

Para manejar correctamente el bloqueo de la vigilia y programar la reproducción, utilicé WakefulIntentService de CommonsWare.

Eso no es una opción apropiada.

Desafortunadamente, el hilo de trabajo de IntentService se cierra inmediatamente después de llamar a MediaPlayer.play () y no se llama a los oyentes registrados de MediaPlayer.

Por eso no es una elección apropiada. Todos los derechos reservados

La pregunta es, ¿cómo puedo hacer que el hilo de trabajo no salga antes de dejarlo hacerlo (es decir, el ha sido procesado y el método onCompletion () se ha llamado por última vez?

No utilice WakefulIntentService . No utilice IntentService . Utilice Service . Administre el WakeLock usted mismo, y llame a stopSelf() en el servicio cuando el audio esté terminado.

El problema con MediaPlayer es que almacena en caché un controlador en el subproceso actual cuando se crea una instancia. En caso de que el subproceso actual no tenga Looper, el valor predeterminado es el subproceso principal. Utilizará este controlador para ejecutar las devoluciones de llamada de los oyentes.

Digamos que instanciar al jugador y utilizarlo dentro de un hilo de servicio. Si llama a los métodos del reproductor a través del servicio, y luego este hilo de servicio muere, el jugador intentará llamar las devoluciones de llamada a los oyentes registrados usando un manejador que apunta al hilo fallecido y lanzará la excepción mostrada en la pregunta.

He encontrado MediaPlayer muy difícil y poco fiable. La solución más simple es usar el reproductor en el hilo principal. Son llamadas cortas, no deben aumentar ANR's.

  • Cómo utilizar la biblioteca ijkplayer
  • ¿Existe una mejor manera de guardar archivos de streaming con MediaPlayer?
  • Cómo jugar a m3u8 en Android?
  • Uso de WakeLock para mantener una reproducción en secuencia
  • Detener y iniciar música en las llamadas entrantes
  • Cambiar URI de MediaPlayer
  • Android MediaPlayer Streaming desde un redireccionamiento PHP no funciona-out!
  • Los archivos mp3 de baja calidad no se reproducen correctamente como se esperaba
  • Subtítulos / Soporte de subtítulos en Android
  • Imagen de botón de reproducción / pausa en la notificación, Android
  • ¿Cuál es la mejor manera de obtener una duración de archivo de audio en Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.