I have a music service that plays music in the background of the app. I want the music to keep playing through all activities of the application but to stop when the app is running in the background (ie when the user goes to another app or presses the home button without removing the app from the running applications)
This is my MusicService code:
public class MusicService extends Service {
public static MediaPlayer player;
public IBinder onBind(Intent arg0) {
return null;
}
public int onStartCommand(Intent intent, int flags, int startId) {
player= MediaPlayer.create(this,R.raw.music1);
player.start();
player.setLooping(true);
return super.onStartCommand(intent,flags,startId);
}
}
and this is the part of my manifest related to the music service:
<service android:name=".MusicService" android:stopWithTask="true" />
Edit: If anyone knows how to play background music without service also that would be okay as long as the music plays during the whole time the app is open and closes when the home button is pressed.
Basicaly you have to define witch activity is your exit point and then edit your onStartCommand like this
private boolean playing; // use this var to determine if the service is playing
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
if(action == ACTION_PLAY) {
// No each time your start an activity start the service with ACTION_PLAY but in ACTION_PLAY process check if the player if not already runing
if(!playing) {
player= MediaPlayer.create(this,R.raw.music1);
player.start();
player.setLooping(true);
// here you set playing to true
playing = true;
}
} else if(action.equals(ACTION_STOP) {
// Set playing to false
playing = false;
// This is just an exemple : Now here increase a delay little bit so that the player will not stop automaticaly after leaving activity
new Handler().postDelayed(new Runnable(){
#override
public void run() {
// No before stoping the play service
// check playing if playing dont go further
if(playing) return;
if(player!=null && player.isPlaying()) {
player.stop();
player.release();
player.reset(); // To avoid mediaPlayer has went away with unhandled error warning
player = null;
// And stop the service
stopSelf();
}
}
},2500);
}
return START_STICKY;}
Now if you want to start playing use
Intent intent = new Intent(context,YourService.class);
intent.setAction(YourService.ACTION_PLAY);
And for stopping
Intent intent = new Intent(context,YourService.class);
intent.setAction(YourService.ACTION_STOP);
And dont forget to define the two action contants fields
If you dont want to define your exit point you can define a boolean that determine that your service is in use and therefore wont be stopped by the delayed handler
Now each time one of activity start, start the service with action ACTION_PLAY
and once it stop start the service with ACTION_STOP that will ensure that each activity have the ability to start and stop player
also dont forget to tweak the delay
Hope it help
I think the best solution to this problem is to stop the music in onPause() of each Activity and start the music in onResume() of each Activity. The problem you will run into is that your music will stutter when your application switches from one Activity to another. To combat that problem, you should post a Runnable (that stops the music) to a Handler in onPause(), but post it so that it doesn't run immediately. It should be delayed for about 200 milliseconds. In onResume(), cancel the Runnable so that it does not run. This will prevent the stuttering, but stop the music 200 milliseconds after the user has pressed the HOME button.
Another option is not to use a Service, but just keep the MediaPlayer instance in your Application class. You'll still want to stop and start the music in onPause() and onResume(), but you can do it more directly by just calling some methods on your Application class. You will need to create a custom Application class that extends Application and add that to your manifest.
Related
OK, here is my code, I'm trying to create a running service even when the app is closed.
In main activity, I have created a new button and call startMyService() to start the service as following:
public void startMyService(View view) {
Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent);
}
the Service class is simple :
public class MyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("MyService", "service is running");
final Uri uri = Settings.System.DEFAULT_RINGTONE_URI;
final Context x =(Context) MyService.this;
new Thread(new Runnable() {
#Override
public void run() {
MediaPlayer player = MediaPlayer.create(x,uri);
player.setLooping(true);
player.start();
}
}).start();
Toast.makeText(getApplicationContext(), "Service is running", Toast.LENGTH_LONG).show();
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
Log.e("MyService", "service done");
}
}
Of course, I have added the service to manifest
<service android:name=".MyService" android:exported="false" android:description="#string/service_description" />
Now after running, I pressed the button to start the service, and close the activity, I supposed the music will be playing in the background but it stopped just after closing the activity.
How to solve this issue? How to make the service still running, and how to make it running again after an android OS destroying it?
I know there are too many topics about android services and START_STICKY
However, as you see this is not working in code above, why?
Note: This is not about playing music in the background, I used playing music because it is the simplest way to know when service is stopped, this is about how to make service keeps running in the background as supposed to be, for example, to do some task like tracking data changes from the server.
It's normal behavior when your application target from android O, if you want to remain your Service you should use startForgroundService with Notification. Read here
While an app is in the foreground, it can create and run both foreground and background services freely. When an app goes into the background, it has a window of several minutes in which it is still allowed to create and use services. At the end of that window, the app is considered to be idle. At this time, the system stops the app's background services, just as if the app had called the services' Service.stopSelf() methods.
I am using a Service class to play music in the background. While I am displaying the notification bar on top, there is issue in my app. When I kill the app, the music stops for about 1 second and then it starts again. I can't figure out what's the issue.
I was following this tutorial.
public class MyMusicService extends Service {
MediaPlayer mediaPlayer;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
public MyMusicService() {
super();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mediaPlayer!= null)
{
mediaPlayer.release();
}
mediaPlayer =MediaPlayer.create(this,R.raw.song);
mediaPlayer.setLooping(true);
mediaPlayer.start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
}
}
Use onTaskRemoved on your main activity and release your mediaplayer on this event.
That tutorial shows you how to build a BACKGROUND service, which can get killed by the system. To play music you should use a FOREGROUND service.
https://developer.android.com/guide/components/services.html#Foreground
According to: https://developer.android.com/reference/android/app/Service.html
Change
START_STICKY
to
START_NOT_STICKY
EDIT:
The issue with music stopping for a while is connected with the fact that you run app and service in the same process. And 'killing app' means stopping the whole process bound to it. What you need to do is to run your service in seperate process:
Start a service in a separate process android
I am using a Service class to play music in the background. While I am displaying the notification bar on top, there is issue in my app. When I kill the app, the music stops for about 1 second and then it starts again. I can't figure out what's the issue.
I was following this tutorial.
public class MyMusicService extends Service {
MediaPlayer mediaPlayer;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
public MyMusicService() {
super();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mediaPlayer!= null)
{
mediaPlayer.release();
}
mediaPlayer =MediaPlayer.create(this,R.raw.song);
mediaPlayer.setLooping(true);
mediaPlayer.start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
}
}
Use onTaskRemoved on your main activity and release your mediaplayer on this event.
That tutorial shows you how to build a BACKGROUND service, which can get killed by the system. To play music you should use a FOREGROUND service.
https://developer.android.com/guide/components/services.html#Foreground
According to: https://developer.android.com/reference/android/app/Service.html
Change
START_STICKY
to
START_NOT_STICKY
EDIT:
The issue with music stopping for a while is connected with the fact that you run app and service in the same process. And 'killing app' means stopping the whole process bound to it. What you need to do is to run your service in seperate process:
Start a service in a separate process android
I have a MediaPlayerService, currently started when the Play/Pause Button on a ListView item is clicked. See code below (CustomListAdapter):
Intent intent = new Intent(v.getContext(),MediaPlayerService.class);
intent.putExtra("StreamLink",audio);
activity.startService(intent);
When this service is started by the code above I want to create a Notification with a Play/Stop button. The user should be able to get out of the app, be able to stop Media Playback e.g. player.stop() and start player.start(). Also when the Notification is clicked it should return the user to the MainActivity.
The code for my MediaPlayerService.java:
public class MediaPlayerService extends Service implements MediaPlayer.OnPreparedListener {
MediaPlayer mMediaPlayer = null;
public String audioStreamLink;
public int onStartCommand(Intent intent, int flags, int startId) {
// Get the Audio Streaming Link from the parsed JSON in the Main Activity
audioStreamLink = intent.getStringExtra("StreamLink");
// Instantiate MediaPlayer, set the Audio Type and acquire a wakelock, set the Media Player Data Source and Prepare.
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mMediaPlayer.setDataSource(audioStreamLink);
} catch (IOException e) {
e.printStackTrace();
}
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.prepareAsync();
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
/** Called when MediaPlayer is ready */
#Override
public void onPrepared(MediaPlayer player) {
player.start();
}
#Override
public void onDestroy() {
mMediaPlayer.stop();
mMediaPlayer.reset();
if (mMediaPlayer != null) mMediaPlayer.release();
}
}
The process of getting a notification is completely documented down there in the documents, for example, see this.
To help you go through all this huge documentation these are the points :
You need to create the custom notification using a NotificationCompat.Builder
A typical music player service would start the notification using startForeground()
To add clickable buttons to the notification use addAction() when building the notifications.
Actions in Notifications are defined by PendingIntent, its a kind of normal Intent when it comes to responding to it.
When a button on the notification is clicked, the onStartCommand() is triggered with the intent you specified for that button (if you configure the intent correctly).
Each button's intent should have a different action so that you can identify the intent when it is received.
Inside the onStartCommand() you can play/pause and do other operations based on this intent's action.
Some reference I would suggest you to read :
https://developer.android.com/guide/topics/ui/notifiers/notifications.html
https://developer.android.com/guide/topics/ui/notifiers/notifications.html#Updating
https://developer.android.com/reference/android/app/Service.html#startForeground(int,android.app.Notification)
Things would have been a bit different if you were using a MediaSession to play the media.
I tried one millions way, but in every way the music keeps playing when i play the HOME button of my mobile.
My last attempt was with application, but i still have the same problem.
This is my code.
public class ProvaMusica extends Application {
Intent musica_backGround;
public Background_music musicaDiBackground = new Background_music();
public void avvia(){
//this is the class where i manage mediaplayer//////////
musica_backGround=new Intent(this, Background_music.class);
startService(musica_backGround);
}
public void onDestroy(){
stopService(musica_backGround);
}
}
In my first activity i use this code to start the music
ProvaMusica appState = ((ProvaMusica)this.getApplication());
appState.avvia();
Now, what should i do to let the music play when showing other activities and make the music stops when my app is not displayed?
I WANT THE MUSIC TO KEEP PLAYING WHILE MOVING FROM AN ACTIVITY TO ANOTHER, I DON'T WANT TO STOP THE MUSIC AND THEN START IT AGAIN, WHEN A NEW ACTIVITY STARTS.
The way I do this is:
I have a singleton class that is the SoundManager.
On onPause each activity calls soundManager.stopPlayingDelayed. This method starts a timer that will call soundManager.checkIfShouldStop in 1 or 2 seconds. It also saves the lastCloseTime to the current time.
Each activity on it's onResume calls soundManager.startPlaying. If already playing the sound manager will ignore the request. This also clears the lastCloseTime
In checkIfShouldStop , if the lastCloseTime is not zero and is more than 1 second ago, it means that after the last activity finished, no new activity of my app was started, so the music should be stopped.
You can have an Application class and set it in AndroidManifest. in its onDestroy() callback, you can use stopService() function to stop the service or you can start the service with an Intent to stop the music.
Your app works as a process in the Android operating system. There are various ways for Android OS to terminate processes and sometimes callback functions like onDestroy() may not be called before the process is killed. Therefore if you start and play your music in a service, the music will play as long as your process lives. However, if you want it to stop, when a specific activity of your app is killed, you can override onDestroy() of that activity and broadcast a message for your service to stop the music. Use a service to implement this.
Maybe i found a way mixing the suggestions all of you gave me.
WITH THIS CODE THE BACKGROUND MUSIC (IN THIS CASE MANAGED WITH A SERVICE) STOPS ONLY WHEN USERS CLOSE THE APP WITH THE BACK BUTTON, WHEN USERS CLOSE THE APP WITH THE HOME BUTTON AND WHEN SCREENS TURN OFF BECAUSE USERS LOCK THE SCREEN WITH THE LOCK BUTTON OF THE DEVICES.
I'd like someone more expert and good at programming than me to confirm this is correct
in this class i check if my current activity is in foreground or not
public class GestioneApplicazioneInBackground{
public static boolean applicazioneInBackground(final Context context) {
ActivityManager am = (ActivityManager) MainActivity.context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
}
in onStop() and onPause() methods of all my activities i have this code
/// if my app and his activities are in background i stop the service i started in my main/first activity////
if(GestioneApplicazioneInBackground.applicazioneInBackground(this) ){
context_of_the_Intent.stopService(intent);
}
else{
// if my app and his activities are NOT in background i check if user turned off the screen with the lock button of the device//////
PowerManager kgMgr = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean showing = kgMgr.isScreenOn();
if(!showing){
context_of_the_Intent.stopService(intent);
}
}
Use this one : Tf you usr media player then Call this method in your activity...
MediaPlayer mp=null;
#Override
protected void onDestroy() {
super.onDestroy();
if (!(mp == null)) {
if (mp.isPlaying()) {
mp.stop();
mp.release();
mp = null;
}
}
};
v #Override
protected void onResume() {
super.onResume();
if (!(mp == null)) {
if (mp.isPlaying()) {
mp.stop();
mp.release();
mp = null;
}
}
};