Binding to a started Service

2.7k views Asked by At

I have a remote Service that I start with startService() then bind to with bindService(). I do this because I want the Service to run in the background until the app explicitly stops it, even if the user closes the Activity with a swipe. Here are the relevant parts of the Service:

public class TrackService extends Service {

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

    @Override
    public IBinder onBind(Intent intent) {
        Log.i("onBind", "got to onBind");
        return trackServiceBinder;
    }
}

Here is the activity:

public class GPSLoggerActivity extends Activity implements ServiceConnection {

    @Override
    protected void onStart() {
        super.onStart();

        Intent intent = new Intent(TrackService.class.getName());
        intent.setClass(getApplicationContext(), TrackService.class);

        startService(intent);
        Log.i("onStart", "started TrackService");

        if (!getApplicationContext().bindService(intent, this, 0)) {
            // close the Activity
        }

        Log.i("onStart", "bound to TrackService");
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.i("onServiceConnected", "got here");

        // get and use the interface from the Binder
    }
}

Here is the manifest for the Service:

    <service
        android:name=".TrackService"
        android:process=":track_service_process"
        android:stopWithTask="false"
        android:label="@string/track_service_label"
        android:exported="false"
        android:enabled="true">
        <intent-filter>
            <action android:name="com.mydomain.gpslogger.TrackService" />
        </intent-filter>
    </service>

When I run this in the debugger step-wise through startService() and bindService() everything is fine. Within the Service, onStartCommand() is invoked followed by onBind(), and in the Activity onServiceConnected() is invoked with the Binder. However, when I'm not debugging, for some reason the Service gets its onBind() method invoked before its onStartCommand() method. Here's the output from the log:

11-28 23:17:01.805: I/onStart(1103): started TrackService
11-28 23:17:01.815: I/onStart(1103): bound to TrackService
11-28 23:17:01.985: I/onBind(1165): got to onBind
11-28 23:17:01.995: I/onStartCommand(1165): got to onStartCommand

The Activity's onServiceConnected() method is never invoked. I've tried using BIND_AUTO_CREATE in the bindService() call, to no effect. It's pretty clear I have some sort of race condition going on here, but I've run this probably 20 times and it always comes out in the same order. The only way I can think of to enforce the correct order of calls in the Service is to put a BroadcastReceiver in the Activity and send an Intent from the onStartCommand() method of the Service to let the Activity know that it's time to call bindService(). That seems pretty kludgy...is there a better way to do this? Or is there something that I'm missing that is causing the out-of-order calls?

1

There are 1 answers

0
David Wasser On

You could call startService() and then wait some period of time before calling bindService(). How long to wait is certainly a question, but I would think if your Service doesn't do massive amounts of work when started, 500 or 1000 milliseconds delay should do it.

I would question why this is important. The Service has an onCreate() method, which is called when the Service is instantiated, regardless of whether onStartCommand() or onBind() is called first. You should be able to setup your architecture so that you do all important setup in onCreate() and then it shouldn't matter in what order onStartCommand() or onBind() is called. NOTE: You must use flag BIND_AUTO_CREATE in the call to bindService()

I also do not understand why the onServiceConnected() method is not called. Unless the call to bindService() returns false (which basically means that Android can't find the Service to bind to), you should get the onServiceConnected() callback. This sounds strange. One possibility is that the Service crashes in onCreate(), or it takes too long to execute the onCreate() method, in which case Android will declare the Service broken.