¿Cómo evitar que Mediaplayer se detenga cuando la pantalla se apaga?

Tengo un mediaplayer en una clase de la Music que se llama de otra Activity secundaria. Funciona bien.

Pero cuando la pantalla se apaga (ya sea por tiempo o botón), la música deja de reproducirse, y al volver y tratar de cerrar la actividad el programa va a "App Not Responding", porque un IllegalStateException en una consulta como mediaplayer.isPlaying() .

¿Cómo puedo evitar que el mediaplayer se detenga cuando la pantalla se apague?

¿Tiene que ser a través de un servicio?

Suponiendo que la respuesta es sí, traté de convertir la clase de Music en un servicio (véase más adelante). También he añadido <service android:enabled="true" android:name=".Music" /> en el Manifest.xml , y estoy llamando a la clase de Music como esta:

 startService(new Intent(getBaseContext(), Music.class)); Music track = Music(fileDescriptor); 

Las únicas 2 nuevas líneas en la actividad principal son startService(new Intent(getBaseContext(), Music.class)); Y stopService(new Intent(getBaseContext(), Music.class)); , Junto con las importaciones correspondientes.

Pero ahora tengo el error InstantiationException porque can't instantiate class al intentar iniciar el servicio. ¿Qué me estoy perdiendo?

Esta es la excepción:

 E/AndroidRuntime(16642): FATAL EXCEPTION: main E/AndroidRuntime(16642): java.lang.RuntimeException: Unable to instantiate service com.floritfoto.apps.ave.Music: java.lang.InstantiationException: can't instantiate class com.floritfoto.apps.ave.Music; no empty constructor E/AndroidRuntime(16642): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2249) E/AndroidRuntime(16642): at android.app.ActivityThread.access$1600(ActivityThread.java:127) E/AndroidRuntime(16642): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1213) E/AndroidRuntime(16642): at android.os.Handler.dispatchMessage(Handler.java:99) E/AndroidRuntime(16642): at android.os.Looper.loop(Looper.java:137) E/AndroidRuntime(16642): at android.app.ActivityThread.main(ActivityThread.java:4507) E/AndroidRuntime(16642): at java.lang.reflect.Method.invokeNative(Native Method) E/AndroidRuntime(16642): at java.lang.reflect.Method.invoke(Method.java:511) E/AndroidRuntime(16642): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980) E/AndroidRuntime(16642): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747) E/AndroidRuntime(16642): at dalvik.system.NativeStart.main(Native Method) E/AndroidRuntime(16642): Caused by: java.lang.InstantiationException: can't instantiate class com.floritfoto.apps.ave.Music; no empty constructor E/AndroidRuntime(16642): at java.lang.Class.newInstanceImpl(Native Method) E/AndroidRuntime(16642): at java.lang.Class.newInstance(Class.java:1319) E/AndroidRuntime(16642): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2246) E/AndroidRuntime(16642): ... 10 more 

Y esta es la Music.class:

 package com.floritfoto.apps.ave; import java.io.FileDescriptor; import java.io.IOException; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.os.IBinder; import android.widget.Toast; public class Music extends Service implements OnCompletionListener{ MediaPlayer mediaPlayer; boolean isPrepared = false; //// TEstes de servico @Override public void onCreate() { super.onCreate(); info("Servico criado!"); } @Override public void onDestroy() { info("Servico fudeu!"); } @Override public void onStart(Intent intent, int startid) { info("Servico started!"); } @Override public IBinder onBind(Intent intent) { return null; } public void info(String txt) { Toast toast = Toast.makeText(getApplicationContext(), txt, Toast.LENGTH_LONG); toast.show(); } //// Fim testes de servico public Music(FileDescriptor fileDescriptor){ mediaPlayer = new MediaPlayer(); try{ mediaPlayer.setDataSource(fileDescriptor); mediaPlayer.prepare(); isPrepared = true; mediaPlayer.setOnCompletionListener(this); } catch(Exception ex){ throw new RuntimeException("Couldn't load music, uh oh!"); } } public void onCompletion(MediaPlayer mediaPlayer) { synchronized(this){ isPrepared = false; } } public void play() { if(mediaPlayer.isPlaying()) return; try{ synchronized(this){ if(!isPrepared){ mediaPlayer.prepare(); } mediaPlayer.seekTo(0); mediaPlayer.start(); } } catch(IllegalStateException ex){ ex.printStackTrace(); } catch(IOException ex){ ex.printStackTrace(); } } public void stop() { mediaPlayer.stop(); synchronized(this){ isPrepared = false; } } public void switchTracks(){ mediaPlayer.seekTo(0); mediaPlayer.pause(); } public void pause() { mediaPlayer.pause(); } public boolean isPlaying() { return mediaPlayer.isPlaying(); } public boolean isLooping() { return mediaPlayer.isLooping(); } public void setLooping(boolean isLooping) { mediaPlayer.setLooping(isLooping); } public void setVolume(float volumeLeft, float volumeRight) { mediaPlayer.setVolume(volumeLeft, volumeRight); } public String getDuration() { return String.valueOf((int)(mediaPlayer.getDuration()/1000)); } public void dispose() { if(mediaPlayer.isPlaying()){ stop(); } mediaPlayer.release(); } } 

Esta línea de Logcat es la importante:

 Caused by: java.lang.InstantiationException: can't instantiate class com.floritfoto.apps.ave.Music; no empty constructor 

Su servicio necesita otro constructor que no tome argumentos:

 public Music() { super("Music"); } 

EDIT :

El uso de un servicio es el enfoque correcto si desea mantener la reproducción de música cuando la pantalla está apagada. Sin embargo, el teléfono intentará dormir cuando la pantalla esté apagada, lo que puede interrumpir su MediaPlayer .

La solución más confiable es utilizar un WakeLock parcial para evitar que el dispositivo se quede dormido mientras está reproduciendo música. Asegúrese de liberar el WakeLock correctamente cuando no esté reproduciendo música activamente; De lo contrario la batería se descargará.

También puede utilizar startForeground() , lo que reducirá el riesgo de que su servicio se destruya cuando hay presión de memoria. También creará una agradable experiencia de usuario al mostrar una notificación persistente cuando se ejecute el servicio.

Instanciar la clase Music con Music track = Music(fileDescriptor); Probablemente está causando algún daño. Un mejor enfoque es pasar el descriptor de archivo como un Extra en el Intent que pasa a startService() :

 Intent serviceIntent = new Intent(this, Music.class); serviceIntent.putExtra("ServiceFileDescriptor", fileDescriptor); startService(serviceIntent); 

A continuación, obtenga el descriptor de archivo de ese mismo Intent cuando se pasa al método onStartCommand() su servicio:

 public int onStartCommand(Intent intent, int flags, int startId) { super.onStart(); Bundle bundle = intent.getExtras(); // NOTE: The next line will vary depending on the data type for the file // descriptor. I'm assuming that it's an int. int fileDescriptor = bundle.getIntExtra("ServiceFileDescriptor"); mediaPlayer = new MediaPlayer(); try { mediaPlayer.setDataSource(fileDescriptor); ... ... return START_STICKY; } 

Algunas cosas a tener en cuenta aquí. He movido el código de su constructor original (que se debe quitar) en onStartCommand() . También puede eliminar el método onStart() , ya que sólo se llamará a los dispositivos pre-2.0. Si quieres soportar versiones modernas de Android, necesitarás usar onStartCommand() lugar. Finalmente, el valor devuelto START_STICKY garantizará que el servicio permanezca en ejecución hasta que usted llame a stopService() de su actividad.

EDIT 2 :

El uso de un servicio permite a los usuarios moverse entre las actividades sin interrumpir el MediaPlayer . No tienes mucho control sobre cuánto tiempo una Activity permanecerá en memoria, pero un Service activo (especialmente si llamas startForeground() ) no se matará a menos que haya una presión de memoria muy fuerte.

Para interactuar con MediaPlayer después de iniciar el servicio, tiene un par de opciones. Puede pasar comandos adicionales al servicio creando Intent y utilizando la cadena de acción (y / o algunos extras) para decirle al servicio qué le gustaría que hiciera. Simplemente llame a startActivity() nuevo con el nuevo Intent , y onStartCommand() será llamado en el servicio, momento en el que puede manipular el MediaPlayer . La segunda opción es usar un servicio enlazado (ejemplo aquí ) y vincular / desvincular cada vez que ingresa o deja una actividad que necesita comunicarse con el servicio. El uso de un servicio enlazado "se siente" como si estuviera manipulando directamente el servicio, pero también es más complejo ya que necesita administrar la vinculación y el desvinculación.

Como opción, puede mantener la pantalla activada para mantener MediaPlayer reproduciendo los medios:

  getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 
  • Cambiar dinámicamente los datos de Custom PreferenceScreen
  • SpinnerPreference? (Cómo incrustar un Spinner en una pantalla de Preferencias)
  • Nueva actividad en Android "entrar desde el lado"
  • ¿Cómo puedo despertar un dispositivo Android y saltar el screenlock
  • Android: PreferenceFragment sólo muestra primera preferencia
  • Android Take Captura de pantalla teléfono enraizado
  • ¿Evita que la orientación de Live Wallpaper cambie cuando se abre una aplicación y se cambia la orientación?
  • La mayoría de los tamaños de pantalla populares / resoluciones en los teléfonos Android
  • Uso de TouchScreens para el control de juegos
  • Después de la rotación de la pantalla, se cambiará el idioma de mi aplicación
  • Desactivar la pantalla mediante programación cuando la cara está cerca de la pantalla en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.