¿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:
- ¿Cómo reproducir los archivos de audio directamente de la carpeta res / raw?
- Reproductor de medios de Android: descargue a archivo y secuencia de archivo
- ¿Cómo hacer una aplicación móvil DLNA android?
- MediaPlayer se detiene y se reinicia
- Android lo que hace exactamente error mediaplayer 1, -107
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; } } }
- Contexto dentro de un Runnable
- Interferencias de AudioManager MODE_IN_CALL
- ANDROID: ¿Hay reproductor multimedia gratuito de terceros para streaming de vídeo MPEG4?
- Error de MediaPlayer de Android (1, -38) y (-38, 0)
- Android - QCMediaPlayer mediaplayer NO está presente - no puede reproducir sonido en absoluto
- VideoView no reproduce vídeo en bucle solo en Galaxy s4
- Android varios MediaPlayers
- Java.io.IOException: setDataSource failed .: status = 0x80000000
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.
- Envío de mayúsculas a un TextEdit durante pruebas instrumentadas
- Cómo establecer el valor predeterminado de SwitchPreference en android?