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?
You could call
startService()
and then wait some period of time before callingbindService()
. How long to wait is certainly a question, but I would think if yourService
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 anonCreate()
method, which is called when theService
is instantiated, regardless of whetheronStartCommand()
oronBind()
is called first. You should be able to setup your architecture so that you do all important setup inonCreate()
and then it shouldn't matter in what orderonStartCommand()
oronBind()
is called. NOTE: You must use flagBIND_AUTO_CREATE
in the call tobindService()
I also do not understand why the
onServiceConnected()
method is not called. Unless the call tobindService()
returnsfalse
(which basically means that Android can't find theService
to bind to), you should get theonServiceConnected()
callback. This sounds strange. One possibility is that theService
crashes inonCreate()
, or it takes too long to execute theonCreate()
method, in which case Android will declare theService
broken.