androidandroid-service-binding

Properly unbind service from activity


I have a simple android app with an activity that binds a service. The basic code is like this:

public class MyActivity extends AppCompatActivity {
    private MyService service;
    private boolean serviceIsBound;

    private final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            service = ((MyService.LocalBinder) binder).getService();
            serviceIsBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            serviceIsBound = false;
        }
    };
    
    // Service gets bound via intent in onCreate()

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (serviceIsBound) {
            service.unbindService(serviceConnection);
        }
    }
}

This produces an error java.lang.IllegalArgumentException: Service not registered in the call service.unbindService(...) when I close the activity.

I tried onStop() instead of onDestroy() --> same error. I tried removing the onDestroy() --> I get an error android.app.ServiceConnectionLeaked. This error of course makes sense -- after all you should clean up your service connections. I just don't know how.


Solution

  • Call unbindService() on the same Context that you call bindService() on. Presumably, given the structure of your sample, you are calling bindService() on the MyActivity instance; if so, call unbindService() on that MyActivity instance as well.


    Note that you probably should not be doing it this way. On a configuration change (e.g., screen rotation), your MyActivity instance will be destroyed and recreated. This means that you will unbind from the service, then bind to it again. If nothing else is bound to that service, and that service is not started, the service will be destroyed (when it is unbound) and then recreated (when the new activity instance binds again).

    It is very likely that you do not need a bound service, particularly if the service is in the same process as the rest of your app. If you are certain that you need a bound service, bind and unbind from something that survives configuration changes, such as an AndroidViewModel. There, you would use the Application as your Context for the bind/unbind calls. Or, if you are using a dependency inversion (DI) framework (e.g., Dagger/Hilt, Koin), you might get a Context from it. Or, if appropriate, bind and unbind from some DI-managed singleton, again using the Application as your `Context.

    FWIW, this sample app contains a bound service. It is used by this client app, which binds and unbinds from a ViewModel.