How to prevent the media player from stopping when turning off the screen?

I have a media planner in the Music class that is being called from another secondary Activity . It works great.

But when the screen turns off (either by a timeout or by a button), the music stops playing, and when it comes back and tries to close the activity, the program goes to the "Do not respond" application, because IllegalStateException when requested, for example mediaplayer.isPlaying() .

How can I prevent the media player from stopping when the screen turns off?

Should it be through the service?

Assuming the answer is yes, I tried to convert the Music class to a service (see below). I also added <service android:enabled="true" android:name=".Music" /> to Manifest.xml , and I call the Music class as follows:

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

Only two new lines in the main activity: startService(new Intent(getBaseContext(), Music.class)); and stopService(new Intent(getBaseContext(), Music.class)); together with relevant imports.

But now I get an InstantiationException error, because can't instantiate class when trying to start the service. What am I missing?

This is an exception:

 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 

and this is 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(); } } 
+4
source share
2 answers

This line from Logcat is important:

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

For your service, you need another constructor that takes no arguments:

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

EDIT

Using the service is the right approach if you want the music to play when the screen is off. However, the phone will try to sleep when the screen is off, and this may interrupt your MediaPlayer .

The most reliable solution is to use partial WakeLock to prevent a sleeping device from playing music. Be sure to release WakeLock correctly if you are not actively playing music; otherwise the battery will run out.

You can also use startForeground() , which will reduce the risk that your service will be killed if there is pressure in memory. It will also create a nice user interface, showing a constant notification when your service is launched.

Creating an instance of the Music class using Music track = Music(fileDescriptor); probably will do some harm. A better approach is to pass the file descriptor as Extra to the Intent that you pass to startService() :

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

Then extract the file descriptor from the same Intent when it passed your onStartCommand() :

 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 an int. int fileDescriptor = bundle.getIntExtra("ServiceFileDescriptor"); mediaPlayer = new MediaPlayer(); try { mediaPlayer.setDataSource(fileDescriptor); ... ... return START_STICKY; } 

A few things to note here. I moved the code from the original constructor (which should be removed) to onStartCommand() . You can also remove the onStart() method, since it will only be called on devices up to 2.0. If you want to support modern versions of Android, you will need to use onStartCommand() . Finally, the return value START_STICKY ensures that the service will continue to function until you call stopService() from your activity.

EDIT 2 :

Using the service allows your users to navigate between activities without interrupting MediaPlayer . You do not have much control over how long the Activity will remain in memory, but the active Service (especially if you call startForeground() ) will not be killed unless there is very strong pressure in the memory.

To interact with MediaPlayer after starting the service, you have several options. You can pass additional commands to the service by creating an Intent and using the action line (and / or some additional functions) to tell the service what you would like to do. Just call startActivity() again with the new Intent , and onStartCommand() will be called in the service, after which you can control MediaPlayer . The second option is to use a linked service (example here ) and bind / untie each time you enter / leave an action that should bind to the service. Using a linked service โ€œfeelsโ€ as if you are directly manipulating the service, but it is also more complex since you need to manage the binding and disconnection.

+5
source

as an option, you can keep the screen turned on to support MediaPlayer playing media:

  getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 
0
source

Source: https://habr.com/ru/post/1442433/


All Articles