Android service crashes after app is swiped out of the recent apps list-ThrowExceptions

Exception or error:

I have a service that gets started (not bound) by an activity. If the activity gets destroyed (e.g. by pressing the back button), the service continues to run, this is of course intended.
However, if I swipe the activity out of the ‘recent apps’ list, the service gets restarted immediately. This is reproducible, every time the activity/app is swiped out of the list, there is a new call to the service’s onCreate-method. No call to onDestroy in between!

First I thought the service gets killed by android, even though I saw no reason for the kill (neither the activity nor the service do resource consuming things, in fact they are minimalistic and do nothing). But then I noticed that the service actually crashes.

V/MainActivity(856): onDestroy // swipe out of the list
I/ActivityManager(287): Killing 856:com.example.myapp/u0a10050: remove task
W/ActivityManager(287): Scheduling restart of crashed service com.example.myapp/.TestService in 5000ms

The code is not noteworthy, but here it is

Activity:

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.v(TAG, "onCreate, starting service...");
        startService(new Intent(this, TestService.class));
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.v(TAG, "onStart");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.v(TAG, "onDestroy");
    }

    //[...]
}

Service:

public class TestService extends Service {

    private static final String TAG = "Service";

    // onBind omitted

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v(TAG, "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.v(TAG, "onDestroy");
    }

}

In short:
My service is independent of the activity’s lifecycle, but only as long as I don’t swipe out the app of the recent apps list. In that case, the service gets restarted but without a call to onDestroy.

Every time this happens, not only the state of the service, but also the work the service is doing is lost. I just want to know why the swipe is the reason for this.

How to solve:

Swiping the app from the recent tasks list actually kills the operating system process that hosts the app. Since your service is running in the same process as your activities, this effectively kills the service. It does NOT call onDestroy() on the service. It just kills the process. Boom. Dead. Gone. Your service does not crash.

Since your service returned START_STICKY from the call to onStartCommand(), Android recognizes that your service should be restarted and schedules a restart of the killed service. However, when your service is restarted it will be in a newly created process (you can see onCreate() called in the service), so it will have to start the work all over again.

Rule #1: Don’t ever swipe apps from the recent tasks list 😉

###

Maybe it can be a problem with Broadcast receivers defined in the manifest.

Do you have some receiver / intent-filter defined in your manifest at application level ? I used to have same kind of problem and it was due to receiver declared in the manifest at the application level

###

By swiping, your process is NOT guaranteed to be killed by the system get killed. No. You only remove the applciation task (or back stack). Application task is NOT equal to the application process.

So if you have any background jobs (threads, services etc) tied to your back stack and you have a good cancellation policy. The system may try to cache your process if it’s suitable for later.

If you kill the app process(es) from the Task Manager though, then it means that your process will be removed and so your JVM/sandbox aggressively by the system.

###

Use *START_NOT_STICKY* as onStartCommand return

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.v(TAG, "onStartCommand");
    return START_NOT_STICKY;
}

Leave a Reply

Your email address will not be published. Required fields are marked *