¿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()
.
- Facebook-Notification like Pullable Screen
- Descripción de la densidad de la pantalla Samsung Galaxy Tab
- Manejo de diferentes tamaños de pantalla (Android)
- Android cómo oler el tamaño de la pantalla de navegador webkit?
- ¿Cómo hacer que mi aplicación se vea igual en todos los dispositivos?
¿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(); } }
- Desactivar la pantalla en android
- ¿Existe una biblioteca de terceros para Android Pinch Zoom
- Orientación de la pantalla de Android NDK
- ListView con diferentes elementos y ViewHolders que conducen a ClassCastException
- Android: detecta mediante programación si el dispositivo tiene una pantalla táctil de hardware conectada
- ¿Cómo crear dos vistas en Android que usan 50% de altura cada una, a menos que sea menor?
- Actividad con una altura específica frente a la lockscreen
- Determinar si el dispositivo tiene pantalla táctil o no
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);
- Comportamiento extraño de la consulta SQLite parametrizada
- Servicio de juegos de Google Play: mostrar el logro desbloqueado