2

A common approach for checking if you have bounded to a service in Android is keeping a boolean parameter such as mBound in your binding steps as described in Android developers guide. I noticed a problem in this Android reference tutorial and I think this approach is somehow a bad practice. Here is the code from Bound Services:

Here is a code block with language code as hint:

public class ActivityMessenger extends Activity {
    Messenger mService = null;
    boolean mBound;

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = new Messenger(service);
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            mService = null;
            mBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}

Ok, Here is the problem. Let's assume that for any reason OnStop() is called immediately after OnStart(). You can create this situation by placing a breakpoint in OnCreate() and wait for your phone screen goes dark that forces an application recreation and then continue application run.

If this situation happens, the mBount variable will be still false when you run OnStop(), because service connection's onServiceConnected() is not called yet. So you will not call unbindService() and you will have a service that you have binded and never unbinded.

Any suggestions for a better approach for Binding services? I wonder if calling unbideService() in any situation is enough or not(for example calling even though service is not binded right now).

Best Regards

Afshin
  • 8,839
  • 1
  • 18
  • 53

1 Answers1

2

I haven't tried this in practice, but it seems reasonable to set mBound = true already when calling bindService instead of in the callback. Actually, the documentation says that you should call unbindService even if bindService returned false (meaning you would never get any onServiceConnected call and mBound would never be true):

Note: If the method returns false, your client does not have a valid connection to the service. However, your client should still call unbindService(); otherwise, your client will keep the service from shutting down when it is idle.

With this in mind it's clear that only setting mBound = true in onServiceConnected is not sufficient (or at least recommended). I would suspect that calling unbindService when not previously bound is a no-op, but that might need some confirmation. If so, setting mBound = true when calling bindService seems like a good approach.

JHH
  • 8,567
  • 8
  • 47
  • 91
  • 1
    `mBound` is normally used to notice complete connection to service which show your `Messenger` is ready to use or you may cause exceptions by accessing `Messenger`. But it seems that you are somehow right about calling `unbindService()`. So I guess it may be better to always call `unbindService()` in `onStop()` without checking `mBound` and leave setting `mBound = true` for `onServiceConnected` to prevent exceptions for accessing `Messenger`. – Afshin Feb 28 '18 at 19:36