Android: stopService doesn't call onDestroy

First, it's onDestroy, not OnDestroy . Second, you must use the @Override annotation for compile-time checking, so your Service code should look somewhat like this:

@Override
public void onDestroy(){
    Log.v("SERVICE","Service killed");
    player.stop();
    super.onDestroy();  
}

First, you need to clarify how many types of services in Android. AFAIK, there are:

  • Foreground service.
  • Background service.
  • Bound service.
  • Intent service.

These services stop in different ways.

  • Foreground: only stop when you intentionally stop it by calling stopService() in activity or fragment where you start that service or call stopSelf() in its own service. And Please note only these methods trigger service's onDestroy().
  • Background: stopService() and stopSelf() do in the same way as foreground. Moreover, you should know this service is in the same thread with activity or fragment calling it, so if you destroy activity or fragment, this service will stop also, but without calling onDestroy(). It basically destroys underground. Thus, if you want to catch when this service stops you need to add android:stopWithTask="false" when declaring service in Manifest file like this:

    <application>
        //....
        <service android:name=".services.catchingStopService" 
             android:stopWithTask="false" /> 
        //....
    </application>
    

    And now in your service class, you can override this method which triggers whenever this service stops:

    @Override 
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent); 
        // Your job when the service stops. 
    }
    
  • Bound: you need to handle by your self by bindService() and unbindService(), you will find out it's totally the same as starService() and stopService()

  • Intent: this type of service stops by itself when it finishes its jobs. And you can use ResultReceiver to communicate between service and activity or fragment. It's similar to BroadcastReceiver. You can search for example on Google easily.

Summary: base on your purpose, pick the type of service satisfying you. And they all agree with:

  • Don't count on onDestroy() to know when service stops because it sometimes gets called underground; more accurately, onDestroy calls when stopService() or stopSelf() calls (BoundService works in the same way, I think, but by a similar method, maybe unBind(), I did not test yet).
  • Use attribute android:stopWithTask="false", instead to know when the service really stops.
  • All types of service stop when the device shutdown or OS kills it if device leaks of memory.
  • You also should have a look at flag return by onStartCommand() to be able to deal with when services stop like restart service again or something. Here are some keyword you can search:
    • START_STICKY
    • <action android:name="android.intent.action.BOOT_COMPLETED" />
    • <action android:name="android.intent.action.ACTION_SHUTDOWN" />
    • <actionandroid:name="android.intent.action.QUICKBOOT_POWEROFF" />

I had a similar problem even with onDestroy correctly set up - the answer for which could be useful for people coming to this page. For me, onDestroy was not called immediately during stopService, sometimes for a very long time - leaving the service doing work when it should have stopped.

The answer is that this is expected behaviour - I can guess but don't exactly know why. So my solution in this case was to create a public static method to stop the actions of the service manually, which happens at the time it's called, then stopService() will call onDestroy in it's own good time...

In the case for this example (which is probably long gone, I would probably decide to keep the service running until it's expected to quite the app, but provide ways to change audio file, while the service is still active.