Java.lang.illegalStateException se produce al azar al obtener mediaPlayer.getCurrentPosition

Este código funciona bien jugar perfectamente, pero un poco de tiempo al azar va a la próxima canción manualmente se bloquea la aplicación. Sucede al azar

updateSeekBar = new Thread() { @Override public void run() { int runtime = mediaPlayer.getDuration(); int currentPosition = 0; while (currentPosition < runtime) { try { sleep(500); currentPosition = mediaPlayer.getCurrentPosition();//This is where the app crash if (seekBar != null) { seekBar.setProgress(currentPosition); } } catch (InterruptedException e) { e.printStackTrace(); } } } }; 

Informe del accidente

 06-10 22:08:53.160 15351-15560/skydeveloper.me.musicx2 E/AndroidRuntime: FATAL EXCEPTION: Thread-6875 Process: skydeveloper.me.musicx2, PID: 15351 java.lang.IllegalStateException at android.media.MediaPlayer.getCurrentPosition(Native Method) at skydeveloper.me.musicx2.Player$1.run(Player.java:104) 

En este código se comprueba si la posición actual está antes del final, y si es así, espera 500 ms, momento en el que puede ser pasado el final! De hecho, para todos los propósitos prácticos, podría llegar al final apenas un momento después del cheque. Esto no es seguro de hilo, pero hay soluciones de sincronización para mitigar esta condición. Le sugeriría que use una solución más sencilla como esta:

 updateSeekBar = new Thread() { @Override public void run() { int runtime = mediaPlayer.getDuration(); int currentPosition = 0; int adv = 0; while ((adv = ((adv = runtime - currentPosition) < 500)?adv:500) > 2) { try { currentPosition = mediaPlayer.getCurrentPosition(); if (seekBar != null) { seekBar.setProgress(currentPosition); } sleep(adv); } catch (InterruptedException e) { e.printStackTrace(); } catch (IllegalStateException e) { seekBar.setProgress(runtime); break; } } } }; 

Este código primero calcula la diferencia entre currentPosition y la duración y sólo si hay más de 2ms de diferencia que tratará de obtener la nueva posición actual (2ms es sólo un número arbitrario para añadir un margen de seguridad, mientras que sacrificar 2ms de precisión al final .) También el sueño se mueve al final del bucle, lo que se suma al margen de seguridad y también hace que la visualización de la barra de búsqueda más en línea con la posición actual. Por último, hay una declaración de captura agregada en caso de que todo lo demás falla.

Por cierto, mientras que no se muestra en su código, estoy asumiendo que seekBar es final por lo que no hay necesidad de comprobar si hay null cada vez. Tal vez moverlo a la parte superior y salir si es nulo.

En realidad, este problema se produce si Reproductor multimedia está en estado incorrecto.

Si su MediaPlayer está en el estado Initialized-State , no puede llamar a start() . Así que tienes que esperar hasta que tu MediaPlayer esté en la posición Prepared-State . Sólo puede buscar el Reproductor de medios en estado Preparado, Iniciado y Pausado.

Para más detalles, puede consultar: Diagrama de estado del reproductor de medios

También puede realizar la segunda llamada para la posición actual. Como se trata de un problema aleatorio, entonces ignorar y llamar de nuevo el método puede ahorrar.

 mediaPlayer.reset(); try { ....... ....... currentPosition = mediaPlayer.getCurrentPosition(); ...... } catch (IllegalStateException e) { mediaPlayer.reset(); currentPosition = mediaPlayer.getCurrentPosition(); } mediaPlayer.prepareAsync(); 

Enlace de recursos: ¿Qué es este error java.lang.IllegalStateException en MediaPlayer.getCurrentPosition



UPDATE1:

Puede omitir la excepción y realizar una segunda llamada al utilizarla. Espero que pueda ayudarte.

 try { .... currentPosition = mediaPlayer.getCurrentPosition(); .... } catch (final Exception e) { e.printStackTrace(); if (e instanceof IllegalStateException) { // bypass IllegalStateException ....... // You can again call the method and make a counter for deadlock situation or implement your own code according to your situation if (retry) { mediaPlayer.reset(); currentPosition = mediaPlayer.getCurrentPosition(); } else { throw e; } } } 

UPDATE2:

Esto intentará 3 veces para conseguir la posición actual. Si no se encuentra, entonces dará excepción.

  try { .... currentPosition = mediaPlayer.getCurrentPosition(); .... } catch (final Exception e) { e.printStackTrace(); if (e instanceof IllegalStateException) { // bypass IllegalStateException ....... // You can again call the method and make a counter for deadlock situation or implement your own code according to your situation boolean checkAgain = true; int counter = 0; for(int i = 0; i < 2; i++){ if (checkAgain) { mediaPlayer.reset(); currentPosition = mediaPlayer.getCurrentPosition(); if(currentPosition > 0) { checkAgain = false; counter++; } } else { if(counter == 0){ throw e; } } } } } 

UPDATE4:

  1. Un IllegalStateException se lanza si prepare() o prepareAsync() se llama en cualquier otro estado.
  2. Mientras está en estado Preparado, las propiedades tales como volumen de audio / sonido, screenOnWhilePlaying, looping se pueden ajustar invocando los métodos de conjunto correspondientes.

  3. Para iniciar la reproducción, se debe start() . Después de que devuelve start() correctamente, el objeto MediaPlayer se encuentra en el estado Iniciado. IsPlaying () se puede llamar para probar si el objeto MediaPlayer está en el estado Iniciado.

  4. Mientras que en el estado Iniciado, el motor de reproductor interno llama a un método de devolución de llamada OnBufferingUpdateListener.onBufferingUpdate() proporcionado por el usuario si se ha registrado previamente un setOnBufferingUpdateListener(OnBufferingUpdateListener) través de setOnBufferingUpdateListener(OnBufferingUpdateListener) . Esta devolución de llamada permite a las aplicaciones realizar un seguimiento del estado de la memoria intermedia durante la transmisión de audio / vídeo. Llamar start() no tiene efecto en un objeto MediaPlayer que ya está en el estado Started.

Por lo isPlaying() método isPlaying() debe ser verificado. Así que el código se verá como a continuación:

  try { .... currentPosition = mediaPlayer.getCurrentPosition(); .... } catch (final Exception e) { e.printStackTrace(); if (e instanceof IllegalStateException) { // bypass IllegalStateException ....... // You can again call the method and make a counter for deadlock situation or implement your own code according to your situation boolean checkAgain = true; int counter = 0; for(int i = 0; i < 2; i++){ if (checkAgain) { mediaPlayer.reset(); if(mediaPlayer != null & mediaPlayer.isPLaying()) { currentPosition = mediaPlayer.getCurrentPosition(); } else { currentPosition = 0; } if(currentPosition > 0) { checkAgain = false; counter++; } } else { if(counter == 0){ throw e; } } } } } 

Creo que la razón de esto es la línea .sleep () línea. Hace que el subproceso actual se detenga mientras el reproductor de medios puede estar realmente en un estado detenido o liberado.

Los documentos mencionan que llamar a getCurrentPosition () debe ocurrir en uno de los estados válidos :

{Inactivo, Inicializado, Preparado, Iniciado, Detenido, Detenido, ReproducidoCompleto}

Antes de llamar a getCurrentPosition, puede comprobar que el reproductor de medios está jugando comprobando el valor de isPlaying () .

También puede ejecutar su hilo utilizando un temporizador y un TimerTask en lugar de utilizar bucles while y Thread.sleep ();

Puede ser posible, cuando intenta obtener la posición de reproductor de medios en ese momento el jugador ha dejado de publicarse, por lo que debe aplicar bajo condiciones para eso,

  if(mediaPlayer != null & mediaPlayer.isPLaying()) currentPosition = mediaPlayer.getCurrentPosition(); else currentPosition = 0; 

Intente debajo del código,

  handler.postDelayed(new Runnable(){ @Override public void run() { int runtime = mediaPlayer.getDuration(); int currentPosition = 0; while (currentPosition < runtime) { try { if(mediaPlayer != null & mediaPlayer.isPLaying()) currentPosition = mediaPlayer.getCurrentPosition(); else currentPosition = 0; if (seekBar != null) { seekBar.setProgress(currentPosition); } } catch (InterruptedException e) { e.printStackTrace(); } } }, 500); 

Sospecho firmemente que estos métodos no son seguros de hilo. Incluso con el estado de comprobación que la gente está sugiriendo, todavía puede encontrarse con un problema si intercalar otra operación de un hilo diferente que hace que este cheque inútil.

Considere la sincronización en el objeto reproductor multimedia para evitar el acceso concurrente. Tendrás que declarar que el mediaPlayer es definitivo.

 final MediaPlayer mediaPlayer = ... 

Y más tarde (con uno de los cheques sugeridos, no miré para ver si éste era el apropiado):

 synchronized (mediaPlayer) { if (mediaPlayer != null & mediaPlayer.isPlaying()) { currentPosition = mediaPlayer.getCurrentPosition(); } else { currentPosition = 0; } } 

Siga el diagrama de estado: introduzca la descripción de la imagen aquí

Se dará cuenta de que debe llamar a reset () para volver al estado inactivo. Sólo entonces se puede llamar a setDataSource ()

  • Sincronizar el PoolingClientConnectionManager o no
  • Cómo actualizar el mismo EditText con TextWatcher?
  • Permiso de Android denegado al leer / proc / self / exe de un hilo no principal
  • Cómo comprobar si la configuración de la pantalla de giro automático está activada / desactivada en Android 4.0+
  • Descargar un archivo con Android y mostrar el progreso en un ProgressDialog
  • Android - Interfaces y clases internas
  • Android error en tutorial no puede encontrar la variable de símbolo activity_display_message
  • Android Multidex RuntimeException
  • Obtener el valor lux del sensor de luz sin evento onSensorChanged ()?
  • ¿Cómo especificar el tamaño correcto del diálogo en el archivo de disposición XML para el diálogo de Android?
  • Cómo hacer en el artículo seleccionado no elegir automáticamente la primera entrada
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.