Continue Service Even If Application Is Cleared from Recent App

How to keep a service running even when app is cleared?

Try implementing foreground service. foreground service

Foreground service displays notification and is never stopped.

Implement this code snippet in your service

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

Android system killed my service when I clear all recent app

A long running service needs the following to make it less likely to be terminated:

  1. Return START_STICKY from onStartCommand(). With this, system will re-start the service even if it has to be stopped for resources limitations.

  2. When the service is not bound to any UI component (e.g an Activity), The service must go in foreground mode by showing a foreground notification. Foreground services are less likely to be terminated by system.

  3. Set the attribute "stopWithTask"=false in corresponding <service> tag of manifest file.

Also, note that devices from some manufacturers will terminate services even with above properties due to customization:

  1. Custom task managers.
  2. Battery saving features that can prohibit non-system services.

Some application services do need to stay in background and have to be aggressively kept alive. Though this method is not recommended, but following steps can be done:

  1. Add triggers for service start : Such as Boot Complete, and Network Connected broadcasts.

  2. If service receives intents/broadcasts FLAG_RECEIVER_FOREGROUND in the intent.

  3. An extreme resort is to manually schedule a pending intent for service restart, with AlarmManager, when onTaskRemoved() is called.

Also, see:

  1. START_STICKY does not work on Android KitKat

How to restart service after the app is killed from recent tasks

Override onTaskRemoved() in your service and use alarm manager to start the service again. Below is code from our app that does the same and works fine:

@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);

Log.d(TAG, "TASK REMOVED");

PendingIntent service = PendingIntent.getService(
getApplicationContext(),
1001,
new Intent(getApplicationContext(), MyService.class),
PendingIntent.FLAG_ONE_SHOT);

AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
}

As you may want to send location periodically even in the case if the service gets killed on low memory (or for any reason), I suggest you to handle the uncaughtException to restart it after N seconds. This is how we have done in our app that works perfectly:

private Thread.UncaughtExceptionHandler defaultUEH;
private Thread.UncaughtExceptionHandler uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {

@Override
public void uncaughtException(Thread thread, Throwable ex) {
Log.d(TAG, "Uncaught exception start!");
ex.printStackTrace();

//Same as done in onTaskRemoved()
PendingIntent service = PendingIntent.getService(
getApplicationContext(),
1001,
new Intent(getApplicationContext(), MyService.class),
PendingIntent.FLAG_ONE_SHOT);

AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
System.exit(2);
}
};

Note: I THINK and I remember I verified it on Kitkat that START_STICKY does not work on Kitkat and higher API levels. Please verify this for yourself.

MORE:
As you do loc sending periodically, you may have to consider the deep sleep mode. To get things work in deep sleep, use WakefulBroadcastReceiver combined with AlarmManager. Take a look at my other post How to use http in deep sleep mode.

UPDATE:
This solution does not work (in fact need not to work) if user "FORCE STOP" the application from Settings. This is good in fact as restarting the service is not a good way if user himself wants to stop application. So, it is fine.

Cannot keep android service alive after app is closed

Here is an example of foreground service that I use and that works, it remains active when the app is closed. Of course, it also must be started, and for that task the app must be running at a first glance, or a receiver of a boot event must be set, but this is another story.

public class MyService extends Service {
static final int NOTIFICATION_ID = 543;

public static boolean isServiceRunning = false;

@Override
public void onCreate() {
super.onCreate();
startServiceWithNotification();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getAction().equals(C.ACTION_START_SERVICE)) {
startServiceWithNotification();
}
else stopMyService();
return START_STICKY;
}

// In case the service is deleted or crashes some how
@Override
public void onDestroy() {
isServiceRunning = false;
super.onDestroy();
}

@Override
public IBinder onBind(Intent intent) {
// Used only in case of bound services.
return null;
}

void startServiceWithNotification() {
if (isServiceRunning) return;
isServiceRunning = true;

Intent notificationIntent = new Intent(getApplicationContext(), MyActivity.class);
notificationIntent.setAction(C.ACTION_MAIN); // A string containing the action name
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent contentPendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.my_icon);

Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(getResources().getString(R.string.app_name))
.setTicker(getResources().getString(R.string.app_name))
.setContentText(getResources().getString(R.string.my_string))
.setSmallIcon(R.drawable.my_icon)
.setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(contentPendingIntent)
.setOngoing(true)
// .setDeleteIntent(contentPendingIntent) // if needed
.build();
notification.flags = notification.flags | Notification.FLAG_NO_CLEAR; // NO_CLEAR makes the notification stay when the user performs a "delete all" command
startForeground(NOTIFICATION_ID, notification);
}

void stopMyService() {
stopForeground(true);
stopSelf();
isServiceRunning = false;
}
}

Then I run it with

    Intent startIntent = new Intent(getApplicationContext(), MyService.class);
startIntent.setAction(C.ACTION_START_SERVICE);
startService(startIntent);

Please note the two constants used as Actions, these are Strings that must start with the package name.



Related Topics



Leave a reply



Submit