I've got a service that is running in a separate process. I'm finding that after the main process UI thread exits from onDestroy() that my service is being destroyed even though I've provided the application context with the binding and specified BIND_AUTO_CREATE.
In my main process' UI thread onCreate() I've got this binding code:
Intent intent = new Intent(mAppContext, MyService.class);
mAppContext.bindService(intent, mMyServiceConnection, Context.BIND_AUTO_CREATE);
In my main process' UI thread onDestroy() I've got this unbinding code:
mAppContext.unbindService(mMyServiceConnection);
Note that I never call stopService().
Android's documentation for bindService() says:
The service will be considered required by the system only for as long as the calling context exists.
If I'm reading that correctly, because I supplied the application's context, the service is considered required by the system for the life of the application.
I have thought that maybe the application's c开发者_JAVA百科ontext dies with onDestroy(). This is what Android's documentation says for getApplicationContext():
Return the context of the single, global Application object of the current process.
If the application's context dies with onDestroy(), then I think Android has a big issue. The issue is that when the display is rotated, onDestroy() is called (and immediately followed by onCreate()). Thus the effect is that when the display is rotated -- and it occurs quite frequently in my case! -- my service always exits.
Note that the pid of my app's process never changes, i.e. it is the same process. That is important in light of the documentation for getApplicationContext() stating "current process."
Here are what my debug logs show:
04-03 05:15:12.874: DEBUG/MyApp(841): main onDestroy
04-03 05:15:12.895: DEBUG/MyApp(847): service onUnbind 04-03 05:15:12.895: DEBUG/MyApp(847): service onDestroy 04-03 05:15:12.934: DEBUG/MyApp(841): main onCreate 04-03 05:15:12.966: DEBUG/MyApp(847): service onCreate 04-03 05:15:12.975: DEBUG/MyApp(847): service onBind
So my questions are:
1) Is my understanding about binding/unbinding correct?
2) Is there a way to have my service not get destroyed when UI thread's onDestroy() is called?
A hack for question #2 is to never unbind. But I don't like it because then I am leaking a binding every time onDestroy() is called. I could "remember" that I've got one leaked binding, and leak just that one, but then I've got cascaded hacks and it's real ugly.
1) Yes, I think your understanding is correct (I say I think because I think I understand what you're saying ;-) ). The flag you are using means "start this service automatically if somebody tries to bind to it and keep it running as long as somebody is bound to it, but once nobody is bound to it, feel free to kill it".
2) Check out the START_STICKY
flag as described here. That should allow you to start the service and keep it running regardless of what happens to the calling Context
In general, onDestroy()
means your activity is about to be killed. When you rotate the display, the Activity
is killed and recreated. You are responsible for saving any state to the Bundle
in the appropriate method and then restoring it in onCreate()
.
Does your service get killed:
- if there is a second
Activity
on the stack? - if you handle configuration changes?
Why do you need your service to stay alive after your application has been destroyed?
I think the general rule of thumb is that you can't be sure when your activities and services will be killed. If this is blocking something you're trying to achieve, there may be a clever way around it.
Edit - you can actually handle the orientation configuration change so that your activity isn't restarted. For more info see the second half of this answer.
About the "second" Activity
: Image you start activity A
and then activity B
. Now you rotate the screen while B
is showing, causing B
to restart. Will A
be restarted at this point? I'm not sure, but I have a hunch that A
will tend to stay alive and keep your application alive during the orientation change. This might be another strategy for keeping your service alive if that's what you're aiming for.
a service is destroyed only when both of the following are true:
- All calls to bindService() have been matched by corresponding calls to unbindService().
- If somebody called startService(), somebody also called stopService() or the service called stopSelf().
A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's onDestroy() method is called and the service is effectively terminated.
this gives a great solution which is also fairly correct and safe!
say there are 2 activities ('viewer' and 'chat' in this example) that need a service, if both bindService AND startService. Also using the binder they update 'viewer_connected' and 'chat_connected' during onStart and onStop.
Then the service runs a loop in a thread that does this:
public isRunning = true;
while (isRunning) {
if (viewer_connected) {
// send update to viewer activity
}
if (chat_connected) {
// send update to chat activity
}
try {
Thread.sleep(5000);
} catch (Exception e) { isRunning=false; }
// 3 second timeout before destroying service
if (!viewer_connected && !chat_connected) {
try { Thread.sleep(3000); } catch (Exception e) { isRunning=false; }
if (!viewer_connected && !chat_connected) isRunning=false;
}
}
stopSelf();
This works because it needs both the activities to unbind AND the service to stopself() before it destroys the service, meaning there is a timeout before the service gets destroyed.
精彩评论