Reputation: 5542
UPDATE: Previously I couldn't find a well defined pattern as to when my foreground service was being killed. After more debugging with the devices (doesn't happen on all) on which this was happening I found.
1.) A lot of times when I open chrome to load a website the foreground service gets killed. Sometimes even when I am using whatsapp this happens.
2.) There are no exceptions and the stacktrace doesn't show anything useful.
Original Question below:
There are many such questions on StackOverflow but the answers so far that I have read mostly say that it is upto Android and we don't have 100% guarantee that a foreground service will not be killed. Some answers suggest START_STICKY but that is not much helpful in my case.
In my case I have a music player app which has a foreground service. This service gets killed on certain devices, mostly some versions of Xiomi (Android version was 5.1.1). Now I understand that android might be short on memory and so my foreground service is being killed, but then why do other music player apps never go through such termination. What is it that they are doing right that I am not?
I made my service foreground service by using startForeground
. Also I return START_STICKY
in onStartCommand although that doesn't help because the service is restarted after a period of 4-5 sec if killed. To bind my service with my activity I use
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT );
So what exactly can I improve/change in my app to prevent this from happening, if other apps are working right there must be something that is wrong in my case. Can someone please help. Thanks in advance !!
Edit:
This is how I call startForeground()
public void sendNotification() {
Intent notIntent = new Intent(this, MainActivity.class);
notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendInt = PendingIntent.getActivity(this, 0,
notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap bitmap = null;
if (!notificationShowing || !forwarded) {
Log.i(TAG, "present");
String title = CommonUtils.getSongFromID(songIndex, this);
bigView.setTextViewText(R.id.title, title);
bigView.setImageViewBitmap(R.id.img, bitmap);
smallView.setTextViewText(R.id.title1, title);
smallView.setImageViewBitmap(R.id.img1, bitmap);
if (pauseButton == 1) {
bigView.setImageViewResource(R.id.pause, R.drawable.pause_noti);
smallView.setImageViewResource(R.id.pause1, R.drawable.pause_noti);
} else {
bigView.setImageViewResource(R.id.pause, R.drawable.play_noti);
smallView.setImageViewResource(R.id.pause1, R.drawable.play_noti);
}
musicNotification = builder.setContentIntent(pendInt)
.setSmallIcon(R.drawable.logo1)
.setTicker(songTitle)
.setOngoing(true)
.setContentTitle("Playing")
.setStyle(new Notification.BigTextStyle().bigText("Song App"))
.setContentText(songTitle)
.setPriority(Notification.PRIORITY_MAX)
.build();
musicNotification.contentView = smallView;
musicNotification.bigContentView = bigView;
musicNotification.contentIntent = pendInt;
Intent switchIntent = new Intent("pause");
switchIntent.putExtra("button", "pause");
PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(this, 100, switchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
bigView.setOnClickPendingIntent(R.id.pause, pendingSwitchIntent);
smallView.setOnClickPendingIntent(R.id.pause1, pendingSwitchIntent);
Intent switchIntent1 = new Intent("forward");
switchIntent1.putExtra("button", "forward");
PendingIntent pendingSwitchIntent2 = PendingIntent.getBroadcast(this, 100, switchIntent1, PendingIntent.FLAG_UPDATE_CURRENT);
bigView.setOnClickPendingIntent(R.id.forward, pendingSwitchIntent2);
smallView.setOnClickPendingIntent(R.id.forward1, pendingSwitchIntent2);
Intent switchIntent2 = new Intent("previous");
switchIntent2.putExtra("button", "previous");
PendingIntent pendingSwitchIntent3 = PendingIntent.getBroadcast(this, 100, switchIntent2, PendingIntent.FLAG_UPDATE_CURRENT);
bigView.setOnClickPendingIntent(R.id.previous, pendingSwitchIntent3);
smallView.setOnClickPendingIntent(R.id.previous1, pendingSwitchIntent3);
Intent switchIntent3 = new Intent("end");
switchIntent3.putExtra("button", "end");
PendingIntent pendingSwitchIntent4 = PendingIntent.getBroadcast(this, 100, switchIntent3, PendingIntent.FLAG_UPDATE_CURRENT);
bigView.setOnClickPendingIntent(R.id.end, pendingSwitchIntent4);
smallView.setOnClickPendingIntent(R.id.end1, pendingSwitchIntent4);
startForeground(NOTIFY_ID, musicNotification);
notificationShowing = true;
}
forwarded = false;
}
Upvotes: 14
Views: 7506
Reputation: 4220
This happened in Xiomi phone due to below reason.
Solution for MIUI 7.0 => Security => Autostart => select Apps that you want to run in background => Reboot After reboot your device should able to run your application services in background like other android devices do.
MIUI AutoStart Detailed Description
And if you looking for other phone then check here is service structure.It automatically restart but when you restart phone call BootReceiver.
public class AppService extends Service {
private class LocalBinder extends Binder {
public AppService getServerInstance() {
return AppService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// If we get killed, after returning from here, restart
return Service.START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
}
}
Thanks hope this will help you.
Upvotes: 9
Reputation: 4374
This service gets killed on certain devices, mostly some versions of Xiomi (Android version was 5.1.1)
Not sure about this, but as per my understanding this might be because of
I don't know whether you use startService() or not. But if you don't then as per this documentation:
You can create a service that is both started and bound. That is, the service can be started by calling
startService()
, which allows the service to run indefinitely, and also allow a client to bind to the service by calling bindService().(This is called Binding to a Started Service)If you do allow your service to be started and bound, then when the service has been started, the system does not destroy the service when all clients unbind. Instead, you must explicitly stop the service, by calling
stopSelf()
orstopService()
.Although you should usually implement either onBind() or onStartCommand(), it's sometimes necessary to implement both. For example, a music player might find it useful to allow its service to run indefinitely and also provide binding. This way, an activity can start the service to play some music and the music continues to play even if the user leaves the application. Then, when the user returns to the application, the activity can bind to the service to regain control of playback.
Be sure to read the section about Managing the Lifecycle of a Bound Service, for more information about the service lifecycle when adding binding to a started service.
onStartCommand
will be called in case of started service so START_STICKY
will work in case of startService()
only.
Update on process logs
Proc # 5: prcp F/S/IF trm: 0 22407:com.wave.music.player/u0a2 (fg-service)
In your process log your player service running in foreground with adj setting prcp (visible foreground service)
which means it's virtually indestructible. Still your service destroyed by OS than there might be very low memory available to run newly launch app. As per this documentation,
There will only ever be a few foreground processes in the system, and these will only be killed as a last resort if memory is so low that not even these processes can continue to run. Generally, at this point, the device has reached a memory paging state, so this action is required in order to keep the user interface responsive.
So I think you are doing nothing wrong. I just want to suggest you to read this official Android developer documentation and try to run your service in separate process(Documentation suggests this approach for music player app). Be careful to implement this as it can easily increase—rather than decrease—your RAM footprint if done incorrectly.
Upvotes: 1