Skip to content Skip to sidebar Skip to footer

Gracefully Clean Up Bound Service When Activity Is Getting Swiped From The Recents

I have a bound service which goes to the foreground when needed. Here's a simplified version of what I have: class MyService extends Service { private static final ServiceConne

Solution 1:

As already mentioned by mklimek, onTaskRemoved() is the way to go for this.

I use it in a project with a bound service that is started and bound by an Activity. Here are the respective parts (I'll add a bit of context to be safe):

Activity calls custom startService() and bindService() helper methods from onCreate():

privatevoidstartService() {
    Intent myServiceIntent = newIntent(this, packageName.MyService.class);
    startService(myServiceIntent);
}

privatevoidbindService() {
    mServiceConnection = newServiceConnection() {
        @OverridepublicvoidonServiceConnected(ComponentName componentName, IBinder iBinder) {
            mService = MyServiceListener.Stub.asInterface(iBinder);

            try {
                mService.registerCallback(myServiceCallback);
                mService.doSomething();
            } catch (RemoteException e) {
                MLog.w(TAG, "Exception on callback registration; Service has probably crashed.");
            }
        }

        @OverridepublicvoidonServiceDisconnected(ComponentName componentName) {
            mService = null;
        }
   };

    if(!myServiceIsBound) {
        Intent myServiceIntent = newIntent(this, packageName.MyService.class);
        bindService(myServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
        myServiceIsBound = true;
        // service is now bound
    } else {
        // service has already been bound
    }

}

Now, to the Service class: in it's onCreate(), I show a notification (which is afaik required for running background services) and set up the Binder:

@OverridepublicvoidonCreate() {
    super.onCreate();

    // Setup Binder for IPC
    mBinder = newMyServiceBinder();

    mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

    [...display notification code...] 
}

Service interface (tell me if that's interesting, otherwise I just leave it out here):

privateclassMyServiceBinderextendsMyServiceListener.Stub {

    @OverridepublicvoidregisterCallback(MyServiceCallback callback)throws RemoteException {
         [...]
    }

    // further methods for the service interface...
}

My onTaskRemoved() and the other lifecycle methods look as follows:

@OverridepublicvoidonTaskRemoved(Intent rootIntent) {
    super.onTaskRemoved(rootIntent);

    // do something adequate here
}


// Lifecycle management@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {
    returnSTART_REDELIVER_INTENT;
}


// Binding@Overridepublic IBinder onBind(Intent intent) {
    return mBinder;
}

@OverridepublicbooleanonUnbind(Intent intent) {
    returnsuper.onUnbind(intent);
}

My onTaskRemoved() is called every time I swipe the Activity from the recent apps list. Are you sure your onTaskRemoved() method is not called (did you put some logging code there)? Also make sure to call the super.onTaskRemoved() method within it.

Our code looks quite similar, except that I put the ServiceConnection setup and Service binding code into the Activity. You moved a lot of this logic into the Service itself.

I can only guess that maybe here lies the problem with the leaking of the Service connection, as your ServiceConnection is a static member of your Service class, and you maintain a reference to your Service from within your ServiceConnection (via your "instance" variable). I'm not sure, but it seems both links are not broken, when the Activity is terminated. Mind, how in my code the ServiceConnection is a member of the Activity, and I clear the reference to mService in onServiceDisconnected() to be safe. Maybe you can refactor this a bit, taking references that cannot be GCed upon Activity termination into account.

Post a Comment for "Gracefully Clean Up Bound Service When Activity Is Getting Swiped From The Recents"